Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .github/templates/README.template.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ like Blocked Endpoints and any sort of Auth.
> [!NOTE]
> Blocked Endpoints can be reactivated by manually configuring them

### Blocked Endpoints
### Endpoints

Because Secured Signal API is just a Proxy you can use all of the [Signal REST API](https://github.com/bbernhard/signal-cli-rest-api/blob/master/doc/EXAMPLES.md) endpoints except for...

Expand All @@ -225,12 +225,27 @@ Because Secured Signal API is just a Proxy you can use all of the [Signal REST A
| **/v1/accounts** |
| **/v1/contacts** |

> [!NOTE]
> Matching works by checking if the requested Endpoints startswith a Blocked or Allowed Endpoint

These Endpoints are blocked by default due to Security Risks, but can be modified by setting `blockedEndpoints` in your config:

```yaml
blockedEndpoints: [/v1/register, /v1/unregister, /v1/qrcodelink, /v1/contacts]
```

Override Blocked Endpoints by explicitly allowing endpoints in `allowedEndpoints`.

| Config (Allow) | (Block) | Result | | | |
| :------------------------------- | :---------------------------------- | :--------: | --- | :---------------: | --- |
| `allowedEndpoints: ["/v2/send"]` | `unset` | **all** | 🛑 | **`/v2/send`** | ✅ |
| `unset` | `blockedEndpoints: ["/v1/receive"]` | **all** | ✅ | **`/v1/receive`** | 🛑 |
| `blockedEndpoints: ["/v2"]` | `allowedEndpoints: ["/v2/send"]` | **`/v2*`** | 🛑 | **`/v2/send`** | ✅ |

```yaml
allowedEndpoints: [/v2/send]
```

### Variables

Placeholders can be added under `variables` and can then be referenced in the Body, Query or URL.
Expand Down
2 changes: 2 additions & 0 deletions examples/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ messageAliases: [{ alias: "msg", score: 100 }]

blockedEndpoints:
- /v1/about
allowedEndpoints:
- /v2/send
46 changes: 43 additions & 3 deletions internals/proxy/middlewares/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package middlewares
import (
"net/http"
"slices"
"strings"

log "github.com/codeshelldev/secured-signal-api/utils/logger"
)
Expand All @@ -15,15 +16,18 @@ func (data EndpointsMiddleware) Use() http.Handler {
next := data.Next

return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
blockedEndpoints := getSettingsByReq(req).BLOCKED_ENDPOINTS
settings := getSettingsByReq(req)

if blockedEndpoints == nil {
blockedEndpoints := settings.BLOCKED_ENDPOINTS
allowedEndpoints := settings.ALLOWED_ENDPOINTS

if blockedEndpoints == nil && allowedEndpoints == nil {
blockedEndpoints = getSettings("*").BLOCKED_ENDPOINTS
}

reqPath := req.URL.Path

if slices.Contains(blockedEndpoints, reqPath) {
if isBlocked(reqPath, allowedEndpoints, blockedEndpoints) {
log.Warn("User tried to access blocked endpoint: ", reqPath)
http.Error(w, "Forbidden", http.StatusForbidden)
return
Expand All @@ -32,3 +36,39 @@ func (data EndpointsMiddleware) Use() http.Handler {
next.ServeHTTP(w, req)
})
}

func isBlocked(endpoint string, allowed []string, blocked []string) bool {
if blocked == nil {
blocked = []string{}
}

if allowed == nil {
allowed = []string{}
}

isExplicitlyBlocked := slices.ContainsFunc(blocked, func(try string) bool {
return strings.HasPrefix(endpoint, try)
})

isExplictlyAllowed := slices.ContainsFunc(allowed, func(try string) bool {
return strings.HasPrefix(endpoint, try)
})

// Block all except explicitly Allowed
if len(blocked) == 0 && len(allowed) != 0 {
return !isExplictlyAllowed
}

// Allow all except explicitly Blocked
if len(allowed) == 0 && len(blocked) != 0{
return isExplicitlyBlocked
}

// Excplicitly Blocked except excplictly Allowed
if len(blocked) != 0 && len(allowed) != 0 {
return isExplicitlyBlocked && !isExplictlyAllowed
}

// Block all
return true
}
7 changes: 7 additions & 0 deletions utils/config/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

middlewareTypes "github.com/codeshelldev/secured-signal-api/internals/proxy/middlewares/types"
"github.com/codeshelldev/secured-signal-api/utils"
log "github.com/codeshelldev/secured-signal-api/utils/logger"
"github.com/knadh/koanf/parsers/yaml"
)
Expand All @@ -26,6 +27,7 @@ type ENV_ struct {

type SETTING_ struct {
BLOCKED_ENDPOINTS []string `koanf:"blockedendpoints"`
ALLOWED_ENDPOINTS []string `koanf:"allowedendpoints"`
VARIABLES map[string]any `koanf:"variables"`
MESSAGE_ALIASES []middlewareTypes.MessageAlias `koanf:"messagealiases"`
}
Expand All @@ -38,6 +40,7 @@ var ENV *ENV_ = &ENV_{
SETTINGS: map[string]*SETTING_{
"*": {
BLOCKED_ENDPOINTS: []string{},
ALLOWED_ENDPOINTS: []string{},
MESSAGE_ALIASES: []middlewareTypes.MessageAlias{},
VARIABLES: map[string]any{},
},
Expand All @@ -63,6 +66,7 @@ func InitEnv() {
config.Unmarshal("variables", &defaultSettings.VARIABLES)

defaultSettings.BLOCKED_ENDPOINTS = config.Strings("blockedendpoints")
defaultSettings.ALLOWED_ENDPOINTS = config.Strings("allowedendpoints")
}

func Load() {
Expand All @@ -87,6 +91,9 @@ func Load() {
InitEnv()

log.Info("Finished Loading Configuration")

log.Dev("Loaded Config:\n" + utils.ToJson(config.All()))
log.Dev("Loaded Token Configs:\n" + utils.ToJson(tokensLayer.All()))
}

func LoadDefaults() {
Expand Down