Skip to content

Commit 5791b3d

Browse files
committed
updated string to type
* added central file for str operations and funcs * fixed and added tests * (fixed) README
1 parent 7065f68 commit 5791b3d

File tree

6 files changed

+251
-117
lines changed

6 files changed

+251
-117
lines changed

.github/templates/README.template.md

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66

77
Get the latest version of the `docker-compose.yaml` file:
88

9-
And add secure Token(s) to `API__TOKEN` / `API__TOKENS`. See [API\_\_TOKEN(s)](#api-tokens)
9+
And add secure Token(s) to `API__TOKEN` / `API__TOKENS`. See [API TOKEN(s)](#api-tokens)
1010

1111
> [!IMPORTANT]
1212
> This Documentation will be using `sec-signal-api:8880` as the service host,
13-
> this **won't work**, instead use your containers IP + Port.
13+
> this **is just for simplicty**, instead use your containers or hosts IP + Port.
1414
> Or a hostname if applicable. See [Reverse Proxy](#reverse-proxy)
1515
1616
```yaml
@@ -47,20 +47,20 @@ Secured Signal API provides 3 Ways to Authenticate
4747

4848
### Bearer
4949

50-
To Authenticate add `Authorization: Bearer API__TOKEN` to your request Headers
50+
To Authenticate add `Authorization: Bearer API_TOKEN` to your request Headers
5151

5252
### Basic Auth
5353

5454
To use Basic Auth as Authorization Method add `Authorization: Basic BASE64_STRING` to your Headers
5555

5656
User is `api` (LOWERCASE)
5757

58-
Formatting for `BASE64_STRING` = `user:API__TOKEN`.
58+
Formatting for `BASE64_STRING` = `user:API_TOKEN`.
5959

6060
example:
6161

6262
```bash
63-
echo "api:API__TOKEN" | base64
63+
echo "api:API_TOKEN" | base64
6464
```
6565

6666
=> `YXBpOkFQSV9LRVkK`
@@ -73,17 +73,17 @@ in this case you can use **Query Auth**.
7373
Here is a simple example:
7474

7575
```bash
76-
curl -X POST http://sec-signal-api:8880/v2/send?@authorization=API__TOKEN
76+
curl -X POST http://sec-signal-api:8880/v2/send?@authorization=API_TOKEN
7777
```
7878

79-
Notice the `@` infront of `authorization`. See [Formatting](#format).
79+
Notice the `@` infront of `authorization`. See [KeyValue Pair Injection](#keyvalue-pair-injection).
8080

8181
### Example
8282

8383
To send a message to 1234567:
8484

8585
```bash
86-
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer API__TOKEN" -d '{"message": "Hello World!", "recipients": ["1234567"]}' http://sec-signal-api:8880/v2/send
86+
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer API_TOKEN" -d '{"message": "Hello World!", "recipients": ["1234567"]}' http://sec-signal-api:8880/v2/send
8787
```
8888

8989
### Advanced
@@ -121,34 +121,41 @@ http://sec-signal-api:8880/v1/receive/{{.NUMBER}}
121121

122122
In some cases you may not be able to access / modify the Request Body, in that case specify needed values in the Request Query:
123123

124-
Supported types include **strings**, **ints** and **arrays**
125-
126124
`http://sec-signal-api:8880/?@key=value`
127125

128-
| type | example |
129-
| :--------- | :------ |
130-
| string | abc |
131-
| int | 123 |
132-
| array | [1,2,3] |
133-
| array(int) | 1,2,3 |
134-
| array(str) | a,b,c |
135-
136-
##### Format
137-
138126
In order to differentiate Injection Queries and _regular_ Queries
139127
you have to add `@` in front of any KeyValue Pair assignment.
140128

129+
Supported types include **strings**, **ints** and **arrays**. See [Formatting](#string-to-type).
130+
141131
## Environment Variables
142132

133+
### String To Type
134+
135+
In the Environment the only allowed type is a string so to not have to always use a json string you can use the following types,
136+
if you format them correctly...
137+
138+
| type | example |
139+
| :--------- | :---------------- |
140+
| string | abc |
141+
| string | +123 |
142+
| int | 123 |
143+
| int | -123 |
144+
| json | {"a":"b","c":"d"} |
145+
| array(int) | [1,2,3] |
146+
| array(str) | [a,b,c] |
147+
148+
This formatting applies to almost every situation where the only (allowed) Input Type is a string and other Output Types are needed.
149+
143150
### API Token(s)
144151

145-
Both `API__TOKEN` and `API__TOKENS` support multiple Tokens seperated by a `,` **Comma**.
152+
Both `API__TOKEN` and `API__TOKENS` support multiple Tokens seperated by a `,` **Comma** and `[]` **Brackets**. See [Formatting](#string-to-type).
146153
During Authentication Secured Signal API will try to match the given Token against the list of Tokens inside of these Variables.
147154

148155
```yaml
149156
environment:
150-
API__TOKEN: "token1, token2, token3"
151-
API__TOKENS: "token1, token2, token3"
157+
API__TOKEN: [token1, token2, token3]
158+
API__TOKENS: [token1, token2, token3]
152159
```
153160
154161
> [!IMPORTANT]
@@ -215,7 +222,7 @@ Set this Environment Variable to automatically provide default Recipients:
215222
```yaml
216223
environment:
217224
RECIPIENTS: |
218-
user.id, 000, 001, group.id,
225+
[ user.id, 000, 001, group.id ]
219226
```
220227

221228
example:

tests/string_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package tests
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
"github.com/codeshelldev/secured-signal-api/utils/safestrings"
8+
)
9+
10+
func TestStringEscaping(t *testing.T) {
11+
str1 := `\#`
12+
13+
res1 := safestrings.IsEscaped(str1, "#")
14+
15+
if !res1 {
16+
t.Error("Expected: ", str1, " == true", "; Got: ", str1, " == ", res1)
17+
}
18+
19+
str2 := "#"
20+
21+
res2 := safestrings.IsEscaped(str2, "#")
22+
23+
if res2 {
24+
t.Error("Expected: ", str2, " == false", "; Got: ", str2, " == ", res2)
25+
}
26+
27+
str3 := `#\#`
28+
29+
res3 := safestrings.Contains(str3, "#")
30+
31+
if !res3 {
32+
t.Error("Expected: ", str3, " == true", "; Got: ", str3, " == ", res3)
33+
}
34+
}
35+
36+
func TestStringEnclosement(t *testing.T) {
37+
str1 := "[enclosed]"
38+
39+
res1 := safestrings.IsEnclosedBy(str1, `[`, `]`)
40+
41+
if !res1 {
42+
t.Error("Expected: ", str1, " == true", "; Got: ", str1, " == ", res1)
43+
}
44+
45+
str2 := `\[enclosed]`
46+
47+
res2 := safestrings.IsEnclosedBy(str2, `[`, `]`)
48+
49+
if res2 {
50+
t.Error("Expected: ", str2, " == false", "; Got: ", str2, " == ", res2)
51+
}
52+
}
53+
54+
func TestStringToType(t *testing.T) {
55+
str1 := `[item1,item2]`
56+
57+
res1 := safestrings.ToType(str1)
58+
59+
if reflect.TypeOf(res1) != reflect.TypeFor[[]string]() {
60+
t.Error("Expected: ", str1, " == []string", "; Got: ", str1, " == ", reflect.TypeOf(res1))
61+
}
62+
63+
str2 := `1`
64+
65+
res2 := safestrings.ToType(str2)
66+
67+
if reflect.TypeOf(res2) != reflect.TypeFor[int]() {
68+
t.Error("Expected: ", str2, " == int", "; Got: ", str2, " == ", reflect.TypeOf(res2))
69+
}
70+
71+
str3 := `{ "key": "value" }`
72+
73+
res3 := safestrings.ToType(str3)
74+
75+
if reflect.TypeOf(res3) != reflect.TypeFor[map[string]any]() {
76+
t.Error("Expected: ", str3, " == map[string]any", "; Got: ", str3, " == ", reflect.TypeOf(res3))
77+
}
78+
}

utils/config/config.go

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import (
88
"strings"
99

1010
middlewares "github.com/codeshelldev/secured-signal-api/internals/proxy/middlewares"
11-
utils "github.com/codeshelldev/secured-signal-api/utils"
1211
log "github.com/codeshelldev/secured-signal-api/utils/logger"
12+
"github.com/codeshelldev/secured-signal-api/utils/safestrings"
1313

1414
"github.com/knadh/koanf/parsers/yaml"
1515
"github.com/knadh/koanf/providers/confmap"
@@ -178,28 +178,5 @@ func normalizeKeys(config *koanf.Koanf) {
178178
func normalizeEnv(key string, value string) (string, any) {
179179
key = strings.ToLower(strings.ReplaceAll(key, "__", "."))
180180

181-
if strings.HasPrefix(value, "{") || strings.HasPrefix(value, "[") {
182-
data, err := utils.GetJsonSafe[any](value)
183-
184-
if data != nil && err == nil {
185-
return key, data
186-
}
187-
}
188-
189-
if strings.Contains(value, ",") {
190-
items := utils.StringToArray(value)
191-
192-
return key, items
193-
}
194-
195-
// Treat `+` prefixed Values as strings
196-
if !strings.HasPrefix(value, "+") {
197-
intValue, intErr := strconv.Atoi(value)
198-
199-
if intErr == nil {
200-
return key, intValue
201-
}
202-
}
203-
204-
return key, value
181+
return key, safestrings.ToType(value)
205182
}

utils/query/query.go

Lines changed: 4 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package query
22

33
import (
4-
"regexp"
5-
"strconv"
64
"strings"
5+
6+
"github.com/codeshelldev/secured-signal-api/utils/safestrings"
77
)
88

99
func ParseRawQuery(raw string) map[string][]string {
@@ -30,55 +30,10 @@ func ParseRawQuery(raw string) map[string][]string {
3030
return result
3131
}
3232

33-
func tryParseInt(str string) (int, bool) {
34-
isInt, err := regexp.MatchString(`^\d+$`, str)
35-
36-
if isInt && err == nil {
37-
intValue, err := strconv.Atoi(str)
38-
39-
if err == nil {
40-
return intValue, true
41-
}
42-
}
43-
44-
return 0, false
45-
}
46-
4733
func ParseTypedQueryValues(values []string) any {
48-
var result any
49-
50-
raw := values[0]
51-
52-
intValue, isInt := tryParseInt(raw)
34+
raw := values[len(values)-1]
5335

54-
if strings.Contains(raw, ",") || (strings.Contains(raw, "[") && strings.Contains(raw, "]")) {
55-
if strings.Contains(raw, "[") && strings.Contains(raw, "]") {
56-
escapedStr := strings.ReplaceAll(raw, "[", "")
57-
escapedStr = strings.ReplaceAll(escapedStr, "]", "")
58-
raw = escapedStr
59-
}
60-
61-
parts := strings.Split(raw, ",")
62-
63-
var list []any
64-
65-
for _, part := range parts {
66-
_intValue, _isInt := tryParseInt(part)
67-
68-
if _isInt {
69-
list = append(list, _intValue)
70-
} else {
71-
list = append(list, part)
72-
}
73-
}
74-
result = list
75-
} else if isInt {
76-
result = intValue
77-
} else {
78-
result = raw
79-
}
80-
81-
return result
36+
return safestrings.ToType(raw)
8237
}
8338

8439
func ParseTypedQuery(query string, matchPrefix string) (map[string]any) {

0 commit comments

Comments
 (0)