Skip to content

Commit 93a670c

Browse files
authored
Merge pull request #53 from CodeShellDev/feat/message-templates
feat: Message Templates
2 parents eabf384 + 98f9ad6 commit 93a670c

File tree

13 files changed

+318
-133
lines changed

13 files changed

+318
-133
lines changed

.github/templates/README.template.md

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ endpoint restrictions, placeholders, flexible configuration
3131
- [Getting Started](#getting-started)
3232
- [Setup](#setup)
3333
- [Usage](#usage)
34-
- [Best Practices](#security-best-practices)
34+
- [Best Practices](#best-practices)
3535
- [Configuration](#configuration)
3636
- [Endpoints](#endpoints)
3737
- [Variables](#variables)
38+
- [Data Aliases](#data-aliases)
39+
- [Message Templates](#message-templates)
3840
- [Contributing](#contributing)
3941
- [Support](#support)
4042
- [License](#license)
@@ -119,31 +121,24 @@ curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer API_T
119121

120122
#### Placeholders
121123

122-
If you are not comfortable / don't want to hardcode your Number for example and/or Recipients in you, may use **Placeholders** in your Request. See [Custom Variables](#variables).
124+
If you are not comfortable / don't want to hardcode your Number for example and/or Recipients in you, may use **Placeholders** in your Request.
123125

124-
These Placeholders can be used in the Request Query or the Body of a Request like so:
126+
You can use [**Variable**](#variables) `{{.NUMBER}}` Placeholders and **Body** Placeholders `{{@data.key}}`.
125127

126-
**Body**
128+
| Type | Example |
129+
| :---- | :--------------------------------------------------------------- |
130+
| Body | `{"number": "{{ .NUMBER }}", "recipients": "{{ .RECIPIENTS }}"}` |
131+
| Query | `http://sec-signal-api:8880/v1/receive/?@number={{.NUMBER}}` |
132+
| Path | `http://sec-signal-api:8880/v1/receive/{{.NUMBER}}` |
133+
134+
You can also combine them:
127135

128136
```json
129137
{
130-
"number": "{{ .NUMBER }}",
131-
"recipients": "{{ .RECIPIENTS }}"
138+
"content": "{{.NUMBER}} -> {{.RECIPIENTS}}"
132139
}
133140
```
134141

135-
**Query**
136-
137-
```
138-
http://sec-signal-api:8880/v1/receive/?@number={{.NUMBER}}
139-
```
140-
141-
**Path**
142-
143-
```
144-
http://sec-signal-api:8880/v1/receive/{{.NUMBER}}
145-
```
146-
147142
#### KeyValue Pair Injection
148143

149144
In some cases you may not be able to access / modify the Request Body, in that case specify needed values in the Request Query:
@@ -153,7 +148,7 @@ In some cases you may not be able to access / modify the Request Body, in that c
153148
In order to differentiate Injection Queries and _regular_ Queries
154149
you have to add `@` in front of any KeyValue Pair assignment.
155150

156-
Supported types include **strings**, **ints** and **arrays**. See [Formatting](#string-to-type).
151+
Supported types include **strings**, **ints**, **arrays** and **json dictionaries**. See [Formatting](#string-to-type).
157152

158153
## Best Practices
159154

@@ -293,12 +288,27 @@ settings:
293288
recipients: ["+123400002", "group.id", "user.id"]
294289
```
295290

296-
### Message Aliases
291+
### Message Templates
297292

298-
To improve compatibility with other services Secured Signal API provides **Message Aliases** for the `message` attribute.
293+
To customize the `message` attribute you can use **Message Templates** to build your message by using other Body Keys and Variables.
294+
Use `messageTemplate` to configure:
295+
296+
```yaml
297+
settings:
298+
messageTemplate: |
299+
Your Message:
300+
{{@message}}.
301+
Sent with Secured Signal API.
302+
```
303+
304+
Use `{{@data.key}}` to reference Body Keys and `{{.KEY}}` for Variables.
305+
306+
### Data Aliases
307+
308+
To improve compatibility with other services Secured Signal API provides **Data Aliases** and a built-in `message` Alias.
299309

300310
<details>
301-
<summary><strong>Default Message Aliases</strong></summary>
311+
<summary><strong>Default `message` Aliases</strong></summary>
302312

303313
| Alias | Score | Alias | Score |
304314
| ------------ | ----- | ---------------- | ----- |
@@ -312,23 +322,27 @@ To improve compatibility with other services Secured Signal API provides **Messa
312322

313323
</details>
314324

315-
Secured Signal API will pick the best scoring Message Alias (if available) to extract the correct message from the Request Body.
325+
Secured Signal API will pick the best scoring Data Alias (if available) to extract set the Key to the correct Value from the Request Body.
316326

317-
Message Aliases can be added by setting `messageAliases` in your config:
327+
Data Aliases can be added by setting `dataAliases` in your config:
318328

319329
```yaml
320330
settings:
321-
messageAliases:
322-
[
323-
{ alias: "msg", score: 80 },
324-
{ alias: "data.message", score: 79 },
325-
{ alias: "array[0].message", score: 78 },
326-
]
331+
dataAliases:
332+
"@message":
333+
[
334+
{ alias: "msg", score: 80 },
335+
{ alias: "data.message", score: 79 },
336+
{ alias: "array[0].message", score: 78 },
337+
]
338+
".NUMBER": [{ alias: "phone_number", score: 100 }]
327339
```
328340

341+
Use `@` for aliasing Body Keys and `.` for aliasing Variables.
342+
329343
### Port
330344

331-
To change the Port which Secured Signal API uses, you need to set `server.port` in your config. (default: `8880`)
345+
To change the Port which Secured Signal API uses, you need to set `service.port` in your config. (default: `8880`)
332346

333347
### Log Level
334348

README.md

Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ endpoint restrictions, placeholders, flexible configuration
3535
- [Configuration](#configuration)
3636
- [Endpoints](#endpoints)
3737
- [Variables](#variables)
38+
- [Message Templates](#message-templates)
3839
- [Contributing](#contributing)
3940
- [Support](#support)
4041
- [License](#license)
@@ -65,10 +66,9 @@ services:
6566
container_name: secured-signal
6667
environment:
6768
API__URL: http://signal-api:8080
68-
SETTINGS__VARIABLES__RECIPIENTS:
69-
'[+123400002, +123400003, +123400004]'
69+
SETTINGS__VARIABLES__RECIPIENTS: "[+123400002, +123400003, +123400004]"
7070
SETTINGS__VARIABLES__NUMBER: "+123400001"
71-
API__TOKENS: '[LOOOOOONG_STRING]'
71+
API__TOKENS: "[LOOOOOONG_STRING]"
7272
ports:
7373
- "8880:8880"
7474
restart: unless-stopped
@@ -100,10 +100,9 @@ services:
100100
container_name: secured-signal
101101
environment:
102102
API__URL: http://signal-api:8080
103-
SETTINGS__VARIABLES__RECIPIENTS:
104-
'[+123400002,+123400003,+123400004]'
103+
SETTINGS__VARIABLES__RECIPIENTS: "[+123400002,+123400003,+123400004]"
105104
SETTINGS__VARIABLES__NUMBER: "+123400001"
106-
API__TOKENS: '[LOOOOOONG_STRING]'
105+
API__TOKENS: "[LOOOOOONG_STRING]"
107106
labels:
108107
- traefik.enable=true
109108
- traefik.http.routers.signal-api.rule=Host(`signal-api.mydomain.com`)
@@ -438,39 +437,6 @@ settings:
438437
recipients: ["+123400002", "group.id", "user.id"]
439438
```
440439

441-
### Message Aliases
442-
443-
To improve compatibility with other services Secured Signal API provides **Message Aliases** for the `message` attribute.
444-
445-
<details>
446-
<summary><strong>Default Message Aliases</strong></summary>
447-
448-
| Alias | Score | Alias | Score |
449-
| ------------ | ----- | ---------------- | ----- |
450-
| msg | 100 | data.content | 9 |
451-
| content | 99 | data.description | 8 |
452-
| description | 98 | data.text | 7 |
453-
| text | 20 | data.summary | 6 |
454-
| summary | 15 | data.details | 5 |
455-
| details | 14 | body | 2 |
456-
| data.message | 10 | data | 1 |
457-
458-
</details>
459-
460-
Secured Signal API will pick the best scoring Message Alias (if available) to extract the correct message from the Request Body.
461-
462-
Message Aliases can be added by setting `messageAliases` in your config:
463-
464-
```yaml
465-
settings:
466-
messageAliases:
467-
[
468-
{ alias: "msg", score: 80 },
469-
{ alias: "data.message", score: 79 },
470-
{ alias: "array[0].message", score: 78 },
471-
]
472-
```
473-
474440
### Port
475441

476442
To change the Port which Secured Signal API uses, you need to set `server.port` in your config. (default: `8880`)

data/defaults.yml

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,26 @@ service:
44
logLevel: info
55

66
settings:
7-
messageAliases:
8-
[
9-
{ alias: msg, score: 100 },
10-
{ alias: content, score: 99 },
11-
{ alias: description, score: 98 },
12-
{ alias: text, score: 20 },
13-
{ alias: summary, score: 15 },
14-
{ alias: details, score: 14 },
7+
dataAliases:
8+
"@message":
9+
[
10+
{ alias: msg, score: 100 },
11+
{ alias: content, score: 99 },
12+
{ alias: description, score: 98 },
13+
{ alias: text, score: 20 },
14+
{ alias: summary, score: 15 },
15+
{ alias: details, score: 14 },
1516

16-
{ alias: data.message, score: 10 },
17-
{ alias: data.content, score: 9 },
18-
{ alias: data.description, score: 8 },
19-
{ alias: data.text, score: 7 },
20-
{ alias: data.summary, score: 6 },
21-
{ alias: data.details, score: 5 },
17+
{ alias: data.message, score: 10 },
18+
{ alias: data.content, score: 9 },
19+
{ alias: data.description, score: 8 },
20+
{ alias: data.text, score: 7 },
21+
{ alias: data.summary, score: 6 },
22+
{ alias: data.details, score: 5 },
2223

23-
{ alias: body, score: 2 },
24-
{ alias: data, score: 1 },
25-
]
24+
{ alias: body, score: 2 },
25+
{ alias: data, score: 1 },
26+
]
2627

2728
variables:
2829
recipients: ${RECIPIENTS}

examples/config.yml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
# Example Config (all configurations shown)
2+
service:
3+
port: 8880
24

35
api:
4-
port: 8880
56
url: http://signal-api:8080
67
tokens: [token1, token2]
78

8-
logLevel: INFO
9+
logLevel: info
910

1011
settings:
12+
messageTemplate: |
13+
You've got a Notification:
14+
{{@message}}
15+
At {{@data.timestamp}} on {{@data.date}}.
16+
Send using {{.NUMBER}}.
17+
1118
variables:
1219
number: "+123400001"
1320
recipients: ["+123400002", "group.id", "user.id"]
1421

15-
messageAliases: [{ alias: "msg", score: 100 }]
22+
dataAliases:
23+
"@message": [{ alias: "msg", score: 100 }]
1624

1725
blockedEndpoints:
1826
- /v1/about

internals/proxy/middlewares/body.go renamed to internals/proxy/middlewares/aliases.go

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,24 @@ import (
1212
request "github.com/codeshelldev/secured-signal-api/utils/request"
1313
)
1414

15-
type BodyMiddleware struct {
15+
type AliasMiddleware struct {
1616
Next http.Handler
1717
}
1818

19-
func (data BodyMiddleware) Use() http.Handler {
19+
func (data AliasMiddleware) Use() http.Handler {
2020
next := data.Next
2121

2222
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
23-
messageAliases := getSettingsByReq(req).MESSAGE_ALIASES
23+
settings := getSettingsByReq(req)
2424

25-
if messageAliases == nil {
26-
messageAliases = getSettings("*").MESSAGE_ALIASES
25+
dataAliases := settings.DATA_ALIASES
26+
27+
if dataAliases == nil {
28+
dataAliases = getSettings("*").DATA_ALIASES
29+
}
30+
31+
if settings.VARIABLES == nil {
32+
settings.VARIABLES = getSettings("*").VARIABLES
2733
}
2834

2935
body, err := request.GetReqBody(w, req)
@@ -38,13 +44,20 @@ func (data BodyMiddleware) Use() http.Handler {
3844
if !body.Empty {
3945
bodyData = body.Data
4046

41-
content, ok := bodyData["message"]
47+
aliasData := processDataAliases(dataAliases, bodyData)
4248

43-
if !ok || content == "" {
49+
for key, value := range aliasData {
50+
prefix := key[:1]
4451

45-
bodyData["message"], bodyData = getMessage(messageAliases, bodyData)
52+
keyWithoutPrefix := key[1:]
4653

47-
modifiedBody = true
54+
switch prefix {
55+
case "@":
56+
bodyData[keyWithoutPrefix] = value
57+
modifiedBody = true
58+
case ".":
59+
settings.VARIABLES[keyWithoutPrefix] = value
60+
}
4861
}
4962
}
5063

@@ -70,32 +83,44 @@ func (data BodyMiddleware) Use() http.Handler {
7083
})
7184
}
7285

73-
func getMessage(aliases []middlewareTypes.MessageAlias, data map[string]any) (string, map[string]any) {
74-
var content string
86+
func processDataAliases(aliases map[string][]middlewareTypes.DataAlias, data map[string]any) (map[string]any) {
87+
aliasData := map[string]any{}
88+
89+
for key, alias := range aliases {
90+
key, value := getData(key, alias, data)
91+
92+
aliasData[key] = value
93+
}
94+
95+
return aliasData
96+
}
97+
98+
func getData(key string, aliases []middlewareTypes.DataAlias, data map[string]any) (string, any) {
7599
var best int
100+
var value any
76101

77102
for _, alias := range aliases {
78103
aliasValue, score, ok := processAlias(alias, data)
79104

80-
if ok && score > best {
81-
content = aliasValue
82-
}
105+
if ok {
106+
if score > best {
107+
value = aliasValue
108+
}
83109

84-
data[alias.Alias] = nil
110+
data[alias.Alias] = nil
111+
}
85112
}
86113

87-
return content, data
114+
return key, value
88115
}
89116

90-
func processAlias(alias middlewareTypes.MessageAlias, data map[string]any) (string, int, bool) {
117+
func processAlias(alias middlewareTypes.DataAlias, data map[string]any) (any, int, bool) {
91118
aliasKey := alias.Alias
92119

93120
value, ok := jsonutils.GetByPath(aliasKey, data)
94121

95-
aliasValue, isStr := value.(string)
96-
97-
if isStr && ok && aliasValue != "" {
98-
return aliasValue, alias.Score, true
122+
if ok && value != nil {
123+
return value, alias.Score, true
99124
} else {
100125
return "", 0, false
101126
}

0 commit comments

Comments
 (0)