More docs, more tests, more docs
parent
29c2fc5472
commit
d714af43c9
|
@ -35,7 +35,7 @@ The command allows you to show the access control list, as well as change it, de
|
||||||
it is called.
|
it is called.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
ntfy access # Shows the entire access control list
|
ntfy access # Shows access control list (alias: 'ntfy user list')
|
||||||
ntfy access USERNAME # Shows access control entries for USERNAME
|
ntfy access USERNAME # Shows access control entries for USERNAME
|
||||||
ntfy access USERNAME TOPIC PERMISSION # Allow/deny access for USERNAME to TOPIC
|
ntfy access USERNAME TOPIC PERMISSION # Allow/deny access for USERNAME to TOPIC
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ Arguments:
|
||||||
- deny (alias: none)
|
- deny (alias: none)
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
ntfy access # Shows entire access control list
|
ntfy access # Shows access control list (alias: 'ntfy user list')
|
||||||
ntfy access phil # Shows access for user phil
|
ntfy access phil # Shows access for user phil
|
||||||
ntfy access phil mytopic rw # Allow read-write access to mytopic for user phil
|
ntfy access phil mytopic rw # Allow read-write access to mytopic for user phil
|
||||||
ntfy access everyone mytopic rw # Allow anonymous read-write access to mytopic
|
ntfy access everyone mytopic rw # Allow anonymous read-write access to mytopic
|
||||||
|
@ -82,6 +82,9 @@ func execUserAccess(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
return resetAccess(c, manager, username, topic)
|
return resetAccess(c, manager, username, topic)
|
||||||
} else if perms == "" {
|
} else if perms == "" {
|
||||||
|
if topic != "" {
|
||||||
|
return errors.New("invalid syntax, please check 'ntfy access --help' for usage details")
|
||||||
|
}
|
||||||
return showAccess(c, manager, username)
|
return showAccess(c, manager, username)
|
||||||
}
|
}
|
||||||
return changeAccess(c, manager, username, topic, perms)
|
return changeAccess(c, manager, username, topic, perms)
|
||||||
|
@ -97,13 +100,13 @@ func changeAccess(c *cli.Context, manager auth.Manager, username string, topic s
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if read && write {
|
if read && write {
|
||||||
fmt.Fprintf(c.App.Writer, "Granted read-write access to topic %s\n\n", topic)
|
fmt.Fprintf(c.App.ErrWriter, "Granted read-write access to topic %s\n\n", topic)
|
||||||
} else if read {
|
} else if read {
|
||||||
fmt.Fprintf(c.App.Writer, "Granted read-only access to topic %s\n\n", topic)
|
fmt.Fprintf(c.App.ErrWriter, "Granted read-only access to topic %s\n\n", topic)
|
||||||
} else if write {
|
} else if write {
|
||||||
fmt.Fprintf(c.App.Writer, "Granted write-only access to topic %s\n\n", topic)
|
fmt.Fprintf(c.App.ErrWriter, "Granted write-only access to topic %s\n\n", topic)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(c.App.Writer, "Revoked all access to topic %s\n\n", topic)
|
fmt.Fprintf(c.App.ErrWriter, "Revoked all access to topic %s\n\n", topic)
|
||||||
}
|
}
|
||||||
return showUserAccess(c, manager, username)
|
return showUserAccess(c, manager, username)
|
||||||
}
|
}
|
||||||
|
@ -121,7 +124,7 @@ func resetAllAccess(c *cli.Context, manager auth.Manager) error {
|
||||||
if err := manager.ResetAccess("", ""); err != nil {
|
if err := manager.ResetAccess("", ""); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintln(c.App.Writer, "Reset access for all users")
|
fmt.Fprintln(c.App.ErrWriter, "Reset access for all users")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +132,7 @@ func resetUserAccess(c *cli.Context, manager auth.Manager, username string) erro
|
||||||
if err := manager.ResetAccess(username, ""); err != nil {
|
if err := manager.ResetAccess(username, ""); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(c.App.Writer, "Reset access for user %s\n\n", username)
|
fmt.Fprintf(c.App.ErrWriter, "Reset access for user %s\n\n", username)
|
||||||
return showUserAccess(c, manager, username)
|
return showUserAccess(c, manager, username)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +140,7 @@ func resetUserTopicAccess(c *cli.Context, manager auth.Manager, username string,
|
||||||
if err := manager.ResetAccess(username, topic); err != nil {
|
if err := manager.ResetAccess(username, topic); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(c.App.Writer, "Reset access for user %s and topic %s\n\n", username, topic)
|
fmt.Fprintf(c.App.ErrWriter, "Reset access for user %s and topic %s\n\n", username, topic)
|
||||||
return showUserAccess(c, manager, username)
|
return showUserAccess(c, manager, username)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +161,9 @@ func showAllAccess(c *cli.Context, manager auth.Manager) error {
|
||||||
|
|
||||||
func showUserAccess(c *cli.Context, manager auth.Manager, username string) error {
|
func showUserAccess(c *cli.Context, manager auth.Manager, username string) error {
|
||||||
users, err := manager.User(username)
|
users, err := manager.User(username)
|
||||||
if err != nil {
|
if err == auth.ErrNotFound {
|
||||||
|
return fmt.Errorf("user %s does not exist", username)
|
||||||
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return showUsers(c, manager, []*auth.User{users})
|
return showUsers(c, manager, []*auth.User{users})
|
||||||
|
@ -166,7 +171,7 @@ func showUserAccess(c *cli.Context, manager auth.Manager, username string) error
|
||||||
|
|
||||||
func showUsers(c *cli.Context, manager auth.Manager, users []*auth.User) error {
|
func showUsers(c *cli.Context, manager auth.Manager, users []*auth.User) error {
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
fmt.Fprintf(c.App.Writer, "User %s (%s)\n", user.Name, user.Role)
|
fmt.Fprintf(c.App.ErrWriter, "User %s (%s)\n", user.Name, user.Role)
|
||||||
if user.Role == auth.RoleAdmin {
|
if user.Role == auth.RoleAdmin {
|
||||||
fmt.Fprintf(c.App.ErrWriter, "- read-write access to all topics (admin role)\n")
|
fmt.Fprintf(c.App.ErrWriter, "- read-write access to all topics (admin role)\n")
|
||||||
} else if len(user.Grants) > 0 {
|
} else if len(user.Grants) > 0 {
|
||||||
|
|
|
@ -99,6 +99,13 @@ Example:
|
||||||
Usage: "Shows a list of users",
|
Usage: "Shows a list of users",
|
||||||
Before: inheritRootReaderFunc,
|
Before: inheritRootReaderFunc,
|
||||||
Action: execUserList,
|
Action: execUserList,
|
||||||
|
Description: `Shows a list of all configured users, including the everyone ('*') user.
|
||||||
|
|
||||||
|
This is a server-only command. It directly reads from the user.db as defined in the server config
|
||||||
|
file server.yml. The command only works if 'auth-file' is properly defined.
|
||||||
|
|
||||||
|
This command is an alias to calling 'ntfy access' (display access control list).
|
||||||
|
`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Description: `Manage users of the ntfy server.
|
Description: `Manage users of the ntfy server.
|
||||||
|
@ -111,7 +118,7 @@ The command allows you to add/remove/change users in the ntfy user database, as
|
||||||
passwords or roles.
|
passwords or roles.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
ntfy user list # Shows list of users
|
ntfy user list # Shows list of users (alias: 'ntfy access')
|
||||||
ntfy user add phil # Add regular user phil
|
ntfy user add phil # Add regular user phil
|
||||||
ntfy user add --role=admin phil # Add admin user phil
|
ntfy user add --role=admin phil # Add admin user phil
|
||||||
ntfy user del phil # Delete user phil
|
ntfy user del phil # Delete user phil
|
||||||
|
|
|
@ -28,7 +28,7 @@ func TestCLI_User_Add_Exists(t *testing.T) {
|
||||||
require.Nil(t, runUserCommand(app, conf, "add", "phil"))
|
require.Nil(t, runUserCommand(app, conf, "add", "phil"))
|
||||||
require.Contains(t, stderr.String(), "user phil added with role user")
|
require.Contains(t, stderr.String(), "user phil added with role user")
|
||||||
|
|
||||||
app, stdin, _, stderr = newTestApp()
|
app, stdin, _, _ = newTestApp()
|
||||||
stdin.WriteString("mypass\nmypass")
|
stdin.WriteString("mypass\nmypass")
|
||||||
err := runUserCommand(app, conf, "add", "phil")
|
err := runUserCommand(app, conf, "add", "phil")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
@ -73,6 +73,44 @@ func TestCLI_User_ChangePass(t *testing.T) {
|
||||||
require.Contains(t, stderr.String(), "changed password for user phil")
|
require.Contains(t, stderr.String(), "changed password for user phil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCLI_User_ChangeRole(t *testing.T) {
|
||||||
|
s, conf, port := newTestServerWithAuth(t)
|
||||||
|
defer test.StopServer(t, s, port)
|
||||||
|
|
||||||
|
// Add user
|
||||||
|
app, stdin, _, stderr := newTestApp()
|
||||||
|
stdin.WriteString("mypass\nmypass")
|
||||||
|
require.Nil(t, runUserCommand(app, conf, "add", "phil"))
|
||||||
|
require.Contains(t, stderr.String(), "user phil added with role user")
|
||||||
|
|
||||||
|
// Change role
|
||||||
|
app, _, _, stderr = newTestApp()
|
||||||
|
require.Nil(t, runUserCommand(app, conf, "change-role", "phil", "admin"))
|
||||||
|
require.Contains(t, stderr.String(), "changed role for user phil to admin")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCLI_User_Delete(t *testing.T) {
|
||||||
|
s, conf, port := newTestServerWithAuth(t)
|
||||||
|
defer test.StopServer(t, s, port)
|
||||||
|
|
||||||
|
// Add user
|
||||||
|
app, stdin, _, stderr := newTestApp()
|
||||||
|
stdin.WriteString("mypass\nmypass")
|
||||||
|
require.Nil(t, runUserCommand(app, conf, "add", "phil"))
|
||||||
|
require.Contains(t, stderr.String(), "user phil added with role user")
|
||||||
|
|
||||||
|
// Delete user
|
||||||
|
app, _, _, stderr = newTestApp()
|
||||||
|
require.Nil(t, runUserCommand(app, conf, "del", "phil"))
|
||||||
|
require.Contains(t, stderr.String(), "user phil removed")
|
||||||
|
|
||||||
|
// Delete user again (does not exist)
|
||||||
|
app, _, _, _ = newTestApp()
|
||||||
|
err := runUserCommand(app, conf, "del", "phil")
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Contains(t, err.Error(), "user phil does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
func newTestServerWithAuth(t *testing.T) (s *server.Server, conf *server.Config, port int) {
|
func newTestServerWithAuth(t *testing.T) (s *server.Server, conf *server.Config, port int) {
|
||||||
conf = server.NewConfig()
|
conf = server.NewConfig()
|
||||||
conf.AuthFile = filepath.Join(t.TempDir(), "user.db")
|
conf.AuthFile = filepath.Join(t.TempDir(), "user.db")
|
||||||
|
|
|
@ -155,7 +155,7 @@ user with `ntfy user add --role=admin ...` and be done with all this (see [examp
|
||||||
**Example commands** (type `ntfy user --help` or `ntfy user COMMAND --help` for more details):
|
**Example commands** (type `ntfy user --help` or `ntfy user COMMAND --help` for more details):
|
||||||
|
|
||||||
```
|
```
|
||||||
ntfy user list # Shows list of users
|
ntfy user list # Shows list of users (alias: 'ntfy access')
|
||||||
ntfy user add phil # Add regular user phil
|
ntfy user add phil # Add regular user phil
|
||||||
ntfy user add --role=admin phil # Add admin user phil
|
ntfy user add --role=admin phil # Add admin user phil
|
||||||
ntfy user del phil # Delete user phil
|
ntfy user del phil # Delete user phil
|
||||||
|
@ -164,13 +164,13 @@ ntfy user change-role phil admin # Make user phil an admin
|
||||||
```
|
```
|
||||||
|
|
||||||
### Access control list (ACL)
|
### Access control list (ACL)
|
||||||
The access control list (ACL) **manages access to topics for non-admin users, and for anonymous access**. Each entry
|
The access control list (ACL) **manages access to topics for non-admin users, and for anonymous access (`everyone`/`*`)**.
|
||||||
represents the access permissions for a user to a specific topic or topic pattern.
|
Each entry represents the access permissions for a user to a specific topic or topic pattern.
|
||||||
|
|
||||||
The ACL can be displayed or modified with the `ntfy access` command:
|
The ACL can be displayed or modified with the `ntfy access` command:
|
||||||
|
|
||||||
```
|
```
|
||||||
ntfy access # Shows the entire access control list
|
ntfy access # Shows access control list (alias: 'ntfy user list')
|
||||||
ntfy access USERNAME # Shows access control entries for USERNAME
|
ntfy access USERNAME # Shows access control entries for USERNAME
|
||||||
ntfy access USERNAME TOPIC PERMISSION # Allow/deny access for USERNAME to TOPIC
|
ntfy access USERNAME TOPIC PERMISSION # Allow/deny access for USERNAME to TOPIC
|
||||||
```
|
```
|
||||||
|
@ -225,6 +225,7 @@ to topic `garagedoor` and all topics starting with the word `alerts` (wildcards)
|
||||||
### Example: Private instance
|
### Example: Private instance
|
||||||
The easiest way to configure a private instance is to set `auth-default-access` to `deny-all` in the `server.yml`:
|
The easiest way to configure a private instance is to set `auth-default-access` to `deny-all` in the `server.yml`:
|
||||||
|
|
||||||
|
=== "/etc/ntfy/server.yml"
|
||||||
``` yaml
|
``` yaml
|
||||||
auth-file "/var/lib/ntfy/user.db"
|
auth-file "/var/lib/ntfy/user.db"
|
||||||
auth-default-access: "deny-all"
|
auth-default-access: "deny-all"
|
||||||
|
|
|
@ -279,7 +279,7 @@ $ curl "ntfy.sh/alerts/json?priority=high&tags=zfs-error"
|
||||||
Available filters (all case-insensitive):
|
Available filters (all case-insensitive):
|
||||||
|
|
||||||
| Filter variable | Alias | Example | Description |
|
| Filter variable | Alias | Example | Description |
|
||||||
|---|---|---|---|
|
|-----------------|---------------------------|------------------------------------|-------------------------------------------------------------------------|
|
||||||
| `message` | `X-Message`, `m` | `ntfy.sh/mytopic?message=lalala` | Only return messages that match this exact message string |
|
| `message` | `X-Message`, `m` | `ntfy.sh/mytopic?message=lalala` | Only return messages that match this exact message string |
|
||||||
| `title` | `X-Title`, `t` | `ntfy.sh/mytopic?title=some+title` | Only return messages that match this exact title string |
|
| `title` | `X-Title`, `t` | `ntfy.sh/mytopic?title=some+title` | Only return messages that match this exact title string |
|
||||||
| `priority` | `X-Priority`, `prio`, `p` | `ntfy.sh/mytopic?p=high,urgent` | Only return messages that match *any priority listed* (comma-separated) |
|
| `priority` | `X-Priority`, `prio`, `p` | `ntfy.sh/mytopic?p=high,urgent` | Only return messages that match *any priority listed* (comma-separated) |
|
||||||
|
@ -296,37 +296,70 @@ $ curl -s ntfy.sh/mytopic1,mytopic2/json
|
||||||
{"id":"Cm02DsxUHb","time":1637182643,"event":"message","topic":"mytopic2","message":"for topic 2"}
|
{"id":"Cm02DsxUHb","time":1637182643,"event":"message","topic":"mytopic2","message":"for topic 2"}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
Depending on whether the server is configured to support [access control](../config.md#access-control), some topics
|
||||||
|
may be read/write protected so that only users with the correct credentials can subscribe or publish to them.
|
||||||
|
To publish/subscribe to protected topics, you can use [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication)
|
||||||
|
with a valid username/password. For your self-hosted server, **be sure to use HTTPS to avoid eavesdropping** and exposing
|
||||||
|
your password.
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -u phil:mypass -s "https://ntfy.example.com/mytopic/json"
|
||||||
|
```
|
||||||
|
|
||||||
## JSON message format
|
## JSON message format
|
||||||
Both the [`/json` endpoint](#subscribe-as-json-stream) and the [`/sse` endpoint](#subscribe-as-sse-stream) return a JSON
|
Both the [`/json` endpoint](#subscribe-as-json-stream) and the [`/sse` endpoint](#subscribe-as-sse-stream) return a JSON
|
||||||
format of the message. It's very straight forward:
|
format of the message. It's very straight forward:
|
||||||
|
|
||||||
|
**Message**:
|
||||||
|
|
||||||
| Field | Required | Type | Example | Description |
|
| Field | Required | Type | Example | Description |
|
||||||
|---|---|---|---|---|
|
|--------------|----------|---------------------------------------------------|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `id` | ✔️ | *string* | `hwQ2YpKdmg` | Randomly chosen message identifier |
|
| `id` | ✔️ | *string* | `hwQ2YpKdmg` | Randomly chosen message identifier |
|
||||||
| `time` | ✔️ | *int* | `1635528741` | Message date time, as Unix time stamp |
|
| `time` | ✔️ | *number* | `1635528741` | Message date time, as Unix time stamp |
|
||||||
| `event` | ✔️ | `open`, `keepalive` or `message` | `message` | Message type, typically you'd be only interested in `message` |
|
| `event` | ✔️ | `open`, `keepalive`, `message`, or `poll_request` | `message` | Message type, typically you'd be only interested in `message` |
|
||||||
| `topic` | ✔️ | *string* | `topic1,topic2` | Comma-separated list of topics the message is associated with; only one for all `message` events, but may be a list in `open` events |
|
| `topic` | ✔️ | *string* | `topic1,topic2` | Comma-separated list of topics the message is associated with; only one for all `message` events, but may be a list in `open` events |
|
||||||
| `message` | - | *string* | `Some message` | Message body; always present in `message` events |
|
| `message` | - | *string* | `Some message` | Message body; always present in `message` events |
|
||||||
| `title` | - | *string* | `Some title` | Message [title](../publish.md#message-title); if not set defaults to `ntfy.sh/<topic>` |
|
| `title` | - | *string* | `Some title` | Message [title](../publish.md#message-title); if not set defaults to `ntfy.sh/<topic>` |
|
||||||
| `tags` | - | *string array* | `["tag1","tag2"]` | List of [tags](../publish.md#tags-emojis) that may or not map to emojis |
|
| `tags` | - | *string array* | `["tag1","tag2"]` | List of [tags](../publish.md#tags-emojis) that may or not map to emojis |
|
||||||
| `priority` | - | *1, 2, 3, 4, or 5* | `4` | Message [priority](../publish.md#message-priority) with 1=min, 3=default and 5=max |
|
| `priority` | - | *1, 2, 3, 4, or 5* | `4` | Message [priority](../publish.md#message-priority) with 1=min, 3=default and 5=max |
|
||||||
|
| `click` | - | *URL* | `https://example.com` | Website opened when notification is [clicked](../publish.md#click-action) |
|
||||||
|
| `attachment` | - | *JSON object* | *see below* | Details about an attachment (name, URL, size, ...) |
|
||||||
|
|
||||||
|
**Attachment** (part of the message, see [attachments](../publish.md#attachments) for details):
|
||||||
|
|
||||||
|
| Field | Required | Type | Example | Description |
|
||||||
|
|-----------|----------|-------------|--------------------------------|-----------------------------------------------------------------------------------------------------------|
|
||||||
|
| `name` | ✔️ | *string* | `attachment.jpg` | Name of the attachment, can be overridden with `X-Filename`, see [attachments](../publish.md#attachments) |
|
||||||
|
| `url` | ✔️ | *URL* | `https://example.com/file.jpg` | URL of the attachment |
|
||||||
|
| `type` | -️ | *mime type* | `image/jpeg` | Mime type of the attachment, only defined if attachment was uploaded to ntfy server |
|
||||||
|
| `size` | -️ | *number* | `33848` | Size of the attachment in bytes, only defined if attachment was uploaded to ntfy server |
|
||||||
|
| `expires` | -️ | *number* | `1635528741` | Attachment expiry date as Unix time stamp, only defined if attachment was uploaded to ntfy server |
|
||||||
|
|
||||||
Here's an example for each message type:
|
Here's an example for each message type:
|
||||||
|
|
||||||
=== "Notification message"
|
=== "Notification message"
|
||||||
``` json
|
``` json
|
||||||
{
|
{
|
||||||
"id": "wze9zgqK41",
|
"id": "sPs71M8A2T",
|
||||||
"time": 1638542110,
|
"time": 1643935928,
|
||||||
"event": "message",
|
"event": "message",
|
||||||
"topic": "phil_alerts",
|
"topic": "mytopic",
|
||||||
"priority": 5,
|
"priority": 5,
|
||||||
"tags": [
|
"tags": [
|
||||||
"warning",
|
"warning",
|
||||||
"skull"
|
"skull"
|
||||||
],
|
],
|
||||||
|
"click": "https://homecam.mynet.lan/incident/1234",
|
||||||
|
"attachment": {
|
||||||
|
"name": "camera.jpg",
|
||||||
|
"type": "image/png",
|
||||||
|
"size": 33848,
|
||||||
|
"expires": 1643946728,
|
||||||
|
"url": "https://ntfy.sh/file/sPs71M8A2T.png"
|
||||||
|
},
|
||||||
"title": "Unauthorized access detected",
|
"title": "Unauthorized access detected",
|
||||||
"message": "Remote access to phils-laptop detected. Act right away."
|
"message": "Movement detected in the yard. You better go check"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -362,12 +395,23 @@ Here's an example for each message type:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
=== "Poll request message"
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"id": "371sevb0pD",
|
||||||
|
"time": 1638542275,
|
||||||
|
"event": "poll_request",
|
||||||
|
"topic": "phil_alerts"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## List of all parameters
|
## List of all parameters
|
||||||
The following is a list of all parameters that can be passed when subscribing to a message. Parameter names are **case-insensitive**,
|
The following is a list of all parameters that can be passed **when subscribing to a message**. Parameter names are **case-insensitive**,
|
||||||
and can be passed as **HTTP headers** or **query parameters in the URL**. They are listed in the table in their canonical form.
|
and can be passed as **HTTP headers** or **query parameters in the URL**. They are listed in the table in their canonical form.
|
||||||
|
|
||||||
| Parameter | Aliases (case-insensitive) | Description |
|
| Parameter | Aliases (case-insensitive) | Description |
|
||||||
|---|---|---|
|
|-------------|----------------------------|---------------------------------------------------------------------------------|
|
||||||
| `poll` | `X-Poll`, `po` | Return cached messages and close connection |
|
| `poll` | `X-Poll`, `po` | Return cached messages and close connection |
|
||||||
| `scheduled` | `X-Scheduled`, `sched` | Include scheduled/delayed messages in message list |
|
| `scheduled` | `X-Scheduled`, `sched` | Include scheduled/delayed messages in message list |
|
||||||
| `message` | `X-Message`, `m` | Filter: Only return messages that match this exact message string |
|
| `message` | `X-Message`, `m` | Filter: Only return messages that match this exact message string |
|
||||||
|
|
|
@ -104,7 +104,7 @@ these are environment variables, you typically don't have to worry about quoting
|
||||||
in double-quotes, you should be fine:
|
in double-quotes, you should be fine:
|
||||||
|
|
||||||
| Variable | Aliases | Description |
|
| Variable | Aliases | Description |
|
||||||
|---|---|---
|
|------------------|----------------------------|----------------------------------------|
|
||||||
| `$NTFY_ID` | `$id` | Unique message ID |
|
| `$NTFY_ID` | `$id` | Unique message ID |
|
||||||
| `$NTFY_TIME` | `$time` | Unix timestamp of the message delivery |
|
| `$NTFY_TIME` | `$time` | Unix timestamp of the message delivery |
|
||||||
| `$NTFY_TOPIC` | `$topic` | Topic name |
|
| `$NTFY_TOPIC` | `$topic` | Topic name |
|
||||||
|
|
Loading…
Reference in New Issue