More docs, more tests, more docs
This commit is contained in:
		
							parent
							
								
									29c2fc5472
								
							
						
					
					
						commit
						d714af43c9
					
				
					 6 changed files with 155 additions and 60 deletions
				
			
		|  | @ -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,10 +225,11 @@ 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`: | ||||||
| 
 | 
 | ||||||
| ``` yaml | === "/etc/ntfy/server.yml" | ||||||
| auth-file "/var/lib/ntfy/user.db" |     ``` yaml | ||||||
| auth-default-access: "deny-all" |     auth-file "/var/lib/ntfy/user.db" | ||||||
| ``` |     auth-default-access: "deny-all" | ||||||
|  |     ``` | ||||||
| 
 | 
 | ||||||
| After that, simply create an `admin` user: | After that, simply create an `admin` user: | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue