mirror of
https://github.com/binwiederhier/ntfy.git
synced 2025-07-20 10:04:08 +00:00
make tests happy
This commit is contained in:
parent
1f2c76e63d
commit
650f492d7d
9 changed files with 27 additions and 210 deletions
|
@ -1440,7 +1440,7 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release
|
|||
* Full [IPv6 support](config.md#ipv6-support) for ntfy and the official ntfy.sh server ([#519](https://github.com/binwiederhier/ntfy/issues/519)/[#1380](https://github.com/binwiederhier/ntfy/pull/1380)/[ansible#4](https://github.com/binwiederhier/ntfy-ansible/pull/4))
|
||||
* Support `X-Client-IP`, `X-Real-IP`, `Forwarded` headers for [rate limiting](config.md#ip-based-rate-limiting) via `proxy-forwarded-header` and `proxy-trusted-hosts` ([#1360](https://github.com/binwiederhier/ntfy/pull/1360)/[#1252](https://github.com/binwiederhier/ntfy/pull/1252), thanks to [@pixitha](https://github.com/pixitha))
|
||||
* Add STDIN support for `ntfy publish` ([#1382](https://github.com/binwiederhier/ntfy/pull/1382), thanks to [@srevn](https://github.com/srevn))
|
||||
* You can now use [Slim-Sprig](https://github.com/go-task/slim-sprig) functions in message/title templates ([#1121](https://github.com/binwiederhier/ntfy/issues/1121), thanks to [@davidatkinsondoyle](https://github.com/davidatkinsondoyle) for reporting and to [@wunter8](https://github.com/wunter8) for implementing)
|
||||
* You can now use a subset of [Sprig](https://github.com/Masterminds/sprig) functions in message/title templates ([#1121](https://github.com/binwiederhier/ntfy/issues/1121), thanks to [@davidatkinsondoyle](https://github.com/davidatkinsondoyle) for reporting and to [@wunter8](https://github.com/wunter8) for implementing)
|
||||
|
||||
**Languages**
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
# OS Functions
|
||||
|
||||
_WARNING:_ These functions can lead to information leakage if not used
|
||||
appropriately.
|
||||
|
||||
_WARNING:_ Some notable implementations of Sprig (such as
|
||||
[Kubernetes Helm](http://helm.sh)) _do not provide these functions for security
|
||||
reasons_.
|
||||
|
||||
## env
|
||||
|
||||
The `env` function reads an environment variable:
|
||||
|
||||
```
|
||||
env "HOME"
|
||||
```
|
||||
|
||||
## expandenv
|
||||
|
||||
To substitute environment variables in a string, use `expandenv`:
|
||||
|
||||
```
|
||||
expandenv "Your path is set to $PATH"
|
||||
```
|
|
@ -1,151 +0,0 @@
|
|||
# Semantic Version Functions
|
||||
|
||||
Some version schemes are easily parseable and comparable. Sprig provides functions
|
||||
for working with [SemVer 2](http://semver.org) versions.
|
||||
|
||||
## semver
|
||||
|
||||
The `semver` function parses a string into a Semantic Version:
|
||||
|
||||
```
|
||||
$version := semver "1.2.3-alpha.1+123"
|
||||
```
|
||||
|
||||
_If the parser fails, it will cause template execution to halt with an error._
|
||||
|
||||
At this point, `$version` is a pointer to a `Version` object with the following
|
||||
properties:
|
||||
|
||||
- `$version.Major`: The major number (`1` above)
|
||||
- `$version.Minor`: The minor number (`2` above)
|
||||
- `$version.Patch`: The patch number (`3` above)
|
||||
- `$version.Prerelease`: The prerelease (`alpha.1` above)
|
||||
- `$version.Metadata`: The build metadata (`123` above)
|
||||
- `$version.Original`: The original version as a string
|
||||
|
||||
Additionally, you can compare a `Version` to another `version` using the `Compare`
|
||||
function:
|
||||
|
||||
```
|
||||
semver "1.4.3" | (semver "1.2.3").Compare
|
||||
```
|
||||
|
||||
The above will return `-1`.
|
||||
|
||||
The return values are:
|
||||
|
||||
- `-1` if the given semver is greater than the semver whose `Compare` method was called
|
||||
- `1` if the version who's `Compare` function was called is greater.
|
||||
- `0` if they are the same version
|
||||
|
||||
(Note that in SemVer, the `Metadata` field is not compared during version
|
||||
comparison operations.)
|
||||
|
||||
## semverCompare
|
||||
|
||||
A more robust comparison function is provided as `semverCompare`. It returns `true` if
|
||||
the constraint matches, or `false` if it does not match. This version supports version ranges:
|
||||
|
||||
- `semverCompare "1.2.3" "1.2.3"` checks for an exact match
|
||||
- `semverCompare "^1.2.0" "1.2.3"` checks that the major and minor versions match, and that the patch
|
||||
number of the second version is _greater than or equal to_ the first parameter.
|
||||
|
||||
The SemVer functions use the [Masterminds semver library](https://github.com/Masterminds/semver),
|
||||
from the creators of Sprig.
|
||||
|
||||
## Basic Comparisons
|
||||
|
||||
There are two elements to the comparisons. First, a comparison string is a list
|
||||
of space or comma separated AND comparisons. These are then separated by || (OR)
|
||||
comparisons. For example, `">= 1.2 < 3.0.0 || >= 4.2.3"` is looking for a
|
||||
comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
|
||||
greater than or equal to 4.2.3.
|
||||
|
||||
The basic comparisons are:
|
||||
|
||||
- `=`: equal (aliased to no operator)
|
||||
- `!=`: not equal
|
||||
- `>`: greater than
|
||||
- `<`: less than
|
||||
- `>=`: greater than or equal to
|
||||
- `<=`: less than or equal to
|
||||
|
||||
_Note, according to the Semantic Version specification pre-releases may not be
|
||||
API compliant with their release counterpart. It says,_
|
||||
|
||||
## Working With Prerelease Versions
|
||||
|
||||
Pre-releases, for those not familiar with them, are used for software releases
|
||||
prior to stable or generally available releases. Examples of prereleases include
|
||||
development, alpha, beta, and release candidate releases. A prerelease may be
|
||||
a version such as `1.2.3-beta.1` while the stable release would be `1.2.3`. In the
|
||||
order of precedence, prereleases come before their associated releases. In this
|
||||
example `1.2.3-beta.1 < 1.2.3`.
|
||||
|
||||
According to the Semantic Version specification prereleases may not be
|
||||
API compliant with their release counterpart. It says,
|
||||
|
||||
> A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version.
|
||||
|
||||
SemVer comparisons using constraints without a prerelease comparator will skip
|
||||
prerelease versions. For example, `>=1.2.3` will skip prereleases when looking
|
||||
at a list of releases while `>=1.2.3-0` will evaluate and find prereleases.
|
||||
|
||||
The reason for the `0` as a pre-release version in the example comparison is
|
||||
because pre-releases can only contain ASCII alphanumerics and hyphens (along with
|
||||
`.` separators), per the spec. Sorting happens in ASCII sort order, again per the
|
||||
spec. The lowest character is a `0` in ASCII sort order
|
||||
(see an [ASCII Table](http://www.asciitable.com/))
|
||||
|
||||
Understanding ASCII sort ordering is important because A-Z comes before a-z. That
|
||||
means `>=1.2.3-BETA` will return `1.2.3-alpha`. What you might expect from case
|
||||
sensitivity doesn't apply here. This is due to ASCII sort ordering which is what
|
||||
the spec specifies.
|
||||
|
||||
## Hyphen Range Comparisons
|
||||
|
||||
There are multiple methods to handle ranges and the first is hyphens ranges.
|
||||
These look like:
|
||||
|
||||
- `1.2 - 1.4.5` which is equivalent to `>= 1.2 <= 1.4.5`
|
||||
- `2.3.4 - 4.5` which is equivalent to `>= 2.3.4 <= 4.5`
|
||||
|
||||
## Wildcards In Comparisons
|
||||
|
||||
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
||||
for all comparison operators. When used on the `=` operator it falls
|
||||
back to the patch level comparison (see tilde below). For example,
|
||||
|
||||
- `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||
- `>= 1.2.x` is equivalent to `>= 1.2.0`
|
||||
- `<= 2.x` is equivalent to `< 3`
|
||||
- `*` is equivalent to `>= 0.0.0`
|
||||
|
||||
## Tilde Range Comparisons (Patch)
|
||||
|
||||
The tilde (`~`) comparison operator is for patch level ranges when a minor
|
||||
version is specified and major level changes when the minor number is missing.
|
||||
For example,
|
||||
|
||||
- `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
|
||||
- `~1` is equivalent to `>= 1, < 2`
|
||||
- `~2.3` is equivalent to `>= 2.3, < 2.4`
|
||||
- `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
|
||||
- `~1.x` is equivalent to `>= 1, < 2`
|
||||
|
||||
## Caret Range Comparisons (Major)
|
||||
|
||||
The caret (`^`) comparison operator is for major level changes once a stable
|
||||
(1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts
|
||||
as the API stability level. This is useful when comparisons of API versions as a
|
||||
major change is API breaking. For example,
|
||||
|
||||
- `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
|
||||
- `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
|
||||
- `^2.3` is equivalent to `>= 2.3, < 3`
|
||||
- `^2.x` is equivalent to `>= 2.0.0, < 3`
|
||||
- `^0.2.3` is equivalent to `>=0.2.3 <0.3.0`
|
||||
- `^0.2` is equivalent to `>=0.2.0 <0.3.0`
|
||||
- `^0.0.3` is equivalent to `>=0.0.3 <0.0.4`
|
||||
- `^0.0` is equivalent to `>=0.0.0 <0.1.0`
|
||||
- `^0` is equivalent to `>=0.0.0 <1.0.0`
|
4
go.mod
4
go.mod
|
@ -32,9 +32,11 @@ require github.com/pkg/errors v0.9.1 // indirect
|
|||
require (
|
||||
firebase.google.com/go/v4 v4.16.1
|
||||
github.com/SherClockHolmes/webpush-go v1.4.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/microcosm-cc/bluemonday v1.0.27
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/stripe/stripe-go/v74 v74.30.0
|
||||
golang.org/x/text v0.26.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -67,7 +69,6 @@ require (
|
|||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
|
||||
github.com/gorilla/css v1.0.1 // indirect
|
||||
|
@ -93,7 +94,6 @@ require (
|
|||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
google.golang.org/appengine/v2 v2.0.6 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
|
||||
|
|
|
@ -1133,11 +1133,7 @@ func replaceTemplate(tpl string, source string) (string, error) {
|
|||
if err := json.Unmarshal([]byte(source), &data); err != nil {
|
||||
return "", errHTTPBadRequestTemplateMessageNotJSON
|
||||
}
|
||||
sprigFuncs := sprig.FuncMap()
|
||||
// remove unsafe functions
|
||||
delete(sprigFuncs, "env")
|
||||
delete(sprigFuncs, "expandenv")
|
||||
t, err := template.New("").Funcs(sprigFuncs).Parse(tpl)
|
||||
t, err := template.New("").Funcs(sprig.FuncMap()).Parse(tpl)
|
||||
if err != nil {
|
||||
return "", errHTTPBadRequestTemplateInvalid
|
||||
}
|
||||
|
|
|
@ -3,16 +3,10 @@ package sprig
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// dfault checks whether `given` is set, and returns default if not set.
|
||||
//
|
||||
// This returns `d` if `given` appears not to be set, and `given` otherwise.
|
||||
|
|
|
@ -11,6 +11,8 @@ import (
|
|||
"strings"
|
||||
ttemplate "text/template"
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/cases"
|
||||
)
|
||||
|
||||
// FuncMap produces the function map.
|
||||
|
@ -107,7 +109,7 @@ var genericMap = map[string]interface{}{
|
|||
"trim": strings.TrimSpace,
|
||||
"upper": strings.ToUpper,
|
||||
"lower": strings.ToLower,
|
||||
"title": strings.Title,
|
||||
"title": cases.Title,
|
||||
"substr": substring,
|
||||
// Switch order so that "foo" | repeat 5
|
||||
"repeat": func(count int, str string) string { return strings.Repeat(str, count) },
|
||||
|
|
|
@ -39,7 +39,7 @@ func mustPush(list interface{}, v interface{}) ([]interface{}, error) {
|
|||
return append(nl, v), nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot push on type %s", tp)
|
||||
return nil, fmt.Errorf("cannot push on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ func mustPrepend(list interface{}, v interface{}) ([]interface{}, error) {
|
|||
return append([]interface{}{v}, nl...), nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot prepend on type %s", tp)
|
||||
return nil, fmt.Errorf("cannot prepend on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ func mustChunk(size int, list interface{}) ([][]interface{}, error) {
|
|||
return nl, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot chunk type %s", tp)
|
||||
return nil, fmt.Errorf("cannot chunk type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ func mustLast(list interface{}) (interface{}, error) {
|
|||
|
||||
return l2.Index(l - 1).Interface(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find last on type %s", tp)
|
||||
return nil, fmt.Errorf("cannot find last on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ func mustFirst(list interface{}) (interface{}, error) {
|
|||
|
||||
return l2.Index(0).Interface(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find first on type %s", tp)
|
||||
return nil, fmt.Errorf("cannot find first on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,7 @@ func mustRest(list interface{}) ([]interface{}, error) {
|
|||
|
||||
return nl, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find rest on type %s", tp)
|
||||
return nil, fmt.Errorf("cannot find rest on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,7 @@ func mustInitial(list interface{}) ([]interface{}, error) {
|
|||
|
||||
return nl, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find initial on type %s", tp)
|
||||
return nil, fmt.Errorf("cannot find initial on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,7 +267,7 @@ func mustReverse(v interface{}) ([]interface{}, error) {
|
|||
|
||||
return nl, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find reverse on type %s", tp)
|
||||
return nil, fmt.Errorf("cannot find reverse on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,7 +298,7 @@ func mustCompact(list interface{}) ([]interface{}, error) {
|
|||
|
||||
return nl, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot compact on type %s", tp)
|
||||
return nil, fmt.Errorf("cannot compact on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,7 +329,7 @@ func mustUniq(list interface{}) ([]interface{}, error) {
|
|||
|
||||
return dest, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find uniq on type %s", tp)
|
||||
return nil, fmt.Errorf("cannot find uniq on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,7 +369,7 @@ func mustWithout(list interface{}, omit ...interface{}) ([]interface{}, error) {
|
|||
|
||||
return res, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find without on type %s", tp)
|
||||
return nil, fmt.Errorf("cannot find without on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -401,7 +401,7 @@ func mustHas(needle interface{}, haystack interface{}) (bool, error) {
|
|||
|
||||
return false, nil
|
||||
default:
|
||||
return false, fmt.Errorf("Cannot find has on type %s", tp)
|
||||
return false, fmt.Errorf("cannot find has on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -457,7 +457,7 @@ func concat(lists ...interface{}) interface{} {
|
|||
res = append(res, l2.Index(i).Interface())
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("Cannot concat type %s as list", tp))
|
||||
panic(fmt.Sprintf("cannot concat type %s as list", tp))
|
||||
}
|
||||
}
|
||||
return res
|
||||
|
|
|
@ -101,7 +101,7 @@ func TestToFloat64(t *testing.T) {
|
|||
if target != toFloat64("102") {
|
||||
t.Errorf("Expected 102")
|
||||
}
|
||||
if 0 != toFloat64("frankie") {
|
||||
if toFloat64("frankie") != 0 {
|
||||
t.Errorf("Expected 0")
|
||||
}
|
||||
if target != toFloat64(uint16(102)) {
|
||||
|
@ -110,10 +110,10 @@ func TestToFloat64(t *testing.T) {
|
|||
if target != toFloat64(uint64(102)) {
|
||||
t.Errorf("Expected 102")
|
||||
}
|
||||
if 102.1234 != toFloat64(float64(102.1234)) {
|
||||
if toFloat64(float64(102.1234)) != 102.1234 {
|
||||
t.Errorf("Expected 102.1234")
|
||||
}
|
||||
if 1 != toFloat64(true) {
|
||||
if toFloat64(true) != 1 {
|
||||
t.Errorf("Expected 102")
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ func TestToInt64(t *testing.T) {
|
|||
if target != toInt64("102") {
|
||||
t.Errorf("Expected 102")
|
||||
}
|
||||
if 0 != toInt64("frankie") {
|
||||
if toInt64("frankie") != 0 {
|
||||
t.Errorf("Expected 0")
|
||||
}
|
||||
if target != toInt64(uint16(102)) {
|
||||
|
@ -149,7 +149,7 @@ func TestToInt64(t *testing.T) {
|
|||
if target != toInt64(float64(102.1234)) {
|
||||
t.Errorf("Expected 102")
|
||||
}
|
||||
if 1 != toInt64(true) {
|
||||
if toInt64(true) != 1 {
|
||||
t.Errorf("Expected 102")
|
||||
}
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ func TestToInt(t *testing.T) {
|
|||
if target != toInt("102") {
|
||||
t.Errorf("Expected 102")
|
||||
}
|
||||
if 0 != toInt("frankie") {
|
||||
if toInt("frankie") != 0 {
|
||||
t.Errorf("Expected 0")
|
||||
}
|
||||
if target != toInt(uint16(102)) {
|
||||
|
@ -186,7 +186,7 @@ func TestToInt(t *testing.T) {
|
|||
if target != toInt(float64(102.1234)) {
|
||||
t.Errorf("Expected 102")
|
||||
}
|
||||
if 1 != toInt(true) {
|
||||
if toInt(true) != 1 {
|
||||
t.Errorf("Expected 102")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue