mirror of
https://github.com/nostr-protocol/nips.git
synced 2024-12-22 16:35:52 -05:00
Add Poll Mechanism
This commit is contained in:
parent
694658ca46
commit
588070774a
164
101.md
164
101.md
|
@ -28,27 +28,52 @@ Event `30168` describes a form as a parametrized replaceable event, with `field`
|
||||||
|
|
||||||
The different tags used to detail the form are described as:
|
The different tags used to detail the form are described as:
|
||||||
|
|
||||||
| Tags | Description |
|
**d** - The unique identifier of a form, for a user
|
||||||
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| d | The unique identifier of a form, for a user |
|
|
||||||
| name | A text serving as the name of the form |
|
|
||||||
| settings | An optional global config for the form. |
|
|
||||||
| field | Contains the following values<table><tr><th>index</th><th>name</th><th>description</th></tr><tbody><tr><td>1</td><td>FieldId</td><td>an id that uniqely identifies a field in the forn</td></tr><tr><td>2</td><td>input-type</td><td>A field that describes the type of value that can be expected as a response to this field, values can be: `text`, `option` or `label`</td></tr><tr><td>3</td><td>label</td><td>A label for the field</td></tr><tr><td>4</td><td>options</td> <td>Only used for input-type option, is a Json stringified array of option Tags.</tr><tr></td><td> - </td> <td> Option Tags </td> <td>Option Tags are defined as: [`<OptionId`>, <`label`>, `<optional config>`], optionId can be any alphanumeric string </td> </tr><tr><td>5</td><td>fieldSettings</td><td>An optional JSON stringified object that contains settings specific to the field, for example `renderElement`, a setting which indicates what UI element to render to the client </td></tr> |
|
|
||||||
|
|
||||||
</tbody></table>
|
**name** - The name of the form`
|
||||||
|
|
||||||
## Responses - Public
|
**settings** - A form wide settings object, that can detail styles and visual representation of the form, certain fields in the object may be client specific
|
||||||
|
|
||||||
Response events are also parametrized replaceable events that are attached to a form(3068 kind event), and the event data is stored in a `kind: 30169` event
|
**field** - contains the description of a form field.
|
||||||
|
|
||||||
|
## Field Tag
|
||||||
|
|
||||||
|
A field tag is described as the following array:
|
||||||
|
`["field", FieldId, InputType, Label, Options, Field Settings ]`
|
||||||
|
|
||||||
|
**FieldId** - Is used to identify the field in the form, can be any alphanumeric string.
|
||||||
|
|
||||||
|
**InputType** - Can be one of: "text", "option", "label". All other types can be derived from the text type.
|
||||||
|
|
||||||
|
**Label** - Value that describes the field, can be a question the user needs feedback eg: "What is your age?"
|
||||||
|
|
||||||
|
**Options** - A stringified array of Options in case the user selected an option type.
|
||||||
|
|
||||||
|
**Field Settings** - A stringified JSON that may contain metadata about a field, like wether the field is a "required" field or "prerequisites" for a field.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
The options array is a stringified Array of Option Tags, where each option tag is
|
||||||
|
represented as:
|
||||||
|
`[<OptionId>, <label>, <optional config>]`
|
||||||
|
|
||||||
|
**OptionId** - Similar to FieldId it is an alphanumeric Id that serves as an identifier for that Id in the form.
|
||||||
|
|
||||||
|
**label** - A label describing the option.
|
||||||
|
|
||||||
|
**Optional Config** - metadata object holds information about the options like "prerequisites".
|
||||||
|
|
||||||
|
## Responses
|
||||||
|
|
||||||
|
Response events are events that are attached to a form(3068 kind event), and the response data is stored in a `kind: 1069` event
|
||||||
|
|
||||||
Response structure:
|
Response structure:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"kind": 30169,
|
"kind": 1069,
|
||||||
"content": "",
|
"content": "",
|
||||||
"tags": [
|
"tags": [
|
||||||
["d", "<pubkey of the form author>:<form identifier>"],
|
|
||||||
["a", "30168:<pubkey of the author>:<form identifier>"],
|
["a", "30168:<pubkey of the author>:<form identifier>"],
|
||||||
[
|
[
|
||||||
"response",
|
"response",
|
||||||
|
@ -67,10 +92,9 @@ for option fields, the response is the id of the option selected. In case of mul
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"kind": 30169,
|
"kind": 1069,
|
||||||
"content": "",
|
"content": "",
|
||||||
"tags": [
|
"tags": [
|
||||||
["d", "<pubkey of the form author>:<formId>"],
|
|
||||||
["a", "30168:<pubkey of the form author>:<formId>"],
|
["a", "30168:<pubkey of the form author>:<formId>"],
|
||||||
[
|
[
|
||||||
"response",
|
"response",
|
||||||
|
@ -83,29 +107,63 @@ for option fields, the response is the id of the option selected. In case of mul
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Editable Responses
|
||||||
|
|
||||||
|
if the form setting allows for editable responses. The latest timestamp event should be used to render the response.
|
||||||
|
|
||||||
|
For uneditable responses, an open timestamp attestion [[03.md]] should be added, the event with an attestation for the earliest time should be used.
|
||||||
|
|
||||||
## Access Control
|
## Access Control
|
||||||
|
|
||||||
In general access is granted by signing the event and encrypting the content with different keys.
|
Access control is managed by sending a set of 3 keys to users using gift wrap events as described in [nip-59](./59.md) but with a few modifications.
|
||||||
the mechanism to share the keys is by encrypting the keys and adding it as key-tags in the event, as well as adding p-tags to notify users.
|
|
||||||
The key tag for `kind:30168` events, should look like.
|
|
||||||
|
|
||||||
`["key","<pubkey for the user>", "<optional relays>", "<Encrypted-View-Key>", "<Encrypted-Signing-key>"]`
|
### Rumor
|
||||||
|
|
||||||
`View-key` : generated during form-creation, this key should used to encrypt/decrypt the `".content"` string in the form template.
|
A kind:18 rumor is created that holds the keys in a "key" tag. An example event is:
|
||||||
`Edit-key/Signing-Key`: Is the key which is used to sign the 30168 event.
|
|
||||||
|
|
||||||
Encryption should be via [nip-44](./44.md) using the conversation key derived from the p-tags pubkey and the signing-key.
|
```json
|
||||||
|
{
|
||||||
|
"created_at": 1718188232,
|
||||||
|
"content": "",
|
||||||
|
"tags": [
|
||||||
|
[
|
||||||
|
"key",
|
||||||
|
"026b71adbdc2fd168c17778311950c40afd33a7e08b4d3159f441cfe37a83882",
|
||||||
|
"ca2f78e4fb0132232fbb673e4517498d2aa95d0cd2f9913d820a3fb91912c2d5",
|
||||||
|
"ce6b464f2aff3ca2aa46359a0b91d28027a0283e2946d9a7dc742d20470cdd52"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"kind": 18,
|
||||||
|
"pubkey": "373a87e2c80114a4c15c422a5c3a59acf36ff383cb534d576aea6b08f8e58ee0",
|
||||||
|
"id": "3e2f775af6867b2220bce59a5c2eacde3e2f405c7fc956af09939f7b02a60771"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
`Encrypted View Key`: The view key should be encrypted as `nip44.encrypt(<View Key>, <Coversation Key derived from users public key and the signing key>)`
|
### Seal
|
||||||
|
|
||||||
`Encrypted Signing Key`: The view key should be encrypted as `nip44.encrypt(<Signing Key>, <Coversation Key derived from users public key and the signing key>)`
|
Works exactly as defined in [[59.md]]
|
||||||
|
|
||||||
In case a participant is a viewer and an editor, both the keys should be added in their "key" tag.
|
### Wrap
|
||||||
In case participant is only a viewer the editor key maybe left blank.
|
|
||||||
|
|
||||||
### Public Forms Public Responses
|
The kind `1059` event also works similar to as described in [[59.md]] except that instead of referencing a users pubkey, we refer to an alias pubkey which is derived by hashing the form event information to the users pubkey as follows:
|
||||||
|
|
||||||
Both the form and the responses are kept unencrypted in the `tags` array and signed by the respective users. Useful for cases like polls.
|
1. The hash function used is SHA256.
|
||||||
|
2. The input to the hash function is: `${30168}:${formAuthor}:${formId}:${userPub}`
|
||||||
|
|
||||||
|
**formAuthor** - The pubkey for the `kind:30168` event
|
||||||
|
**formId** - d-tag of the event
|
||||||
|
**userPub** - pubkey to recepient being given the access.
|
||||||
|
|
||||||
|
### Keys
|
||||||
|
|
||||||
|
The "key" tag in the `kind:18` rumor is represented as:
|
||||||
|
`["key", "<view key>", "<signing key>", "voter key"]`
|
||||||
|
|
||||||
|
- **View Key** - A key which used to encrypt a form content, the view key can make the form viewable.
|
||||||
|
|
||||||
|
- **Signing Key** - The private key to the form event. Anybody with this key WILL BE ABLE TO EDIT THE FORM EVENT.
|
||||||
|
|
||||||
|
- **Voter Key** - A key used to submit a response to the form in a poll-like scenario.
|
||||||
|
|
||||||
### Encrypted Responses.
|
### Encrypted Responses.
|
||||||
|
|
||||||
|
@ -113,7 +171,7 @@ Response tags are added to the `.content` field of the event and encrypted as pe
|
||||||
|
|
||||||
### Private Forms only viewable by a group.
|
### Private Forms only viewable by a group.
|
||||||
|
|
||||||
Form fields should be placed in the `.content` key, nip-44 encrypted by the corresponding public key of the view-key, and the signing key. The selected responders can decrypt the form using the view key. The `tags` array is used to keep track of the allowed-responders identities.
|
Form fields and settings should be ommitted from the tags array and placed in the `.content` key, nip-44 encrypted by the corresponding public key of the view-key, and the signing key. The selected responders can decrypt the form using the view key. The `tags` array is used to keep track of the allowed-responders identities.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
let encryptionKey = nip44.v2.utils.getConversationKey(
|
let encryptionKey = nip44.v2.utils.getConversationKey(
|
||||||
|
@ -123,29 +181,43 @@ let encryptionKey = nip44.v2.utils.getConversationKey(
|
||||||
content = nip44.v2.encrypt(JSON.stringify(form), encryptionKey);
|
content = nip44.v2.encrypt(JSON.stringify(form), encryptionKey);
|
||||||
```
|
```
|
||||||
|
|
||||||
### Public forms editable by a group.
|
They view key is shared as a gift wrap to the participants as described above.
|
||||||
|
|
||||||
A signing key is generated for the group.
|
### Polls
|
||||||
Form fields are in the tag array, and the signing-key is encrypted in the key tag like:
|
|
||||||
`["key", "<pub-key with edit access>", "<relays>","","<encrypted signing key>"]`.
|
|
||||||
The key should be the same that the `30168` event is signed with.
|
|
||||||
The pubkeys with edit access, will also be able to view the form responses.
|
|
||||||
|
|
||||||
Encrypted signing key can be calculated as:
|
There are some important parts for a form(general feedback mechanism) to become a poll.
|
||||||
|
|
||||||
```js
|
1. Only elligeble candidates must be allowed to vote.
|
||||||
let conversationKey = nip44.v2.utils.getConversationKey(
|
2. Participants shouldn't be able to associate a response to another participant.
|
||||||
bytesToHex(signingKey),
|
3. Participants should be a ble to verify their response is counted.
|
||||||
npubHex
|
|
||||||
);
|
All of these conditions can be met by establishing a "Voter Key". The Voter Key is a private key generated by someone with edit access to the form (Issuer).
|
||||||
let encyptedKey = nip44.v2.encrypt(bytesToHex(signingKey), conversationKey);
|
|
||||||
|
The Issuer must then add a "v" tag to the form event, followed by a pubkey corresponding to the voterId.
|
||||||
|
|
||||||
|
The v tag is used to query eligible votes.
|
||||||
|
|
||||||
|
Example form with a voter id.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"content": "",
|
||||||
|
"created_at": 1718186931,
|
||||||
|
"id": "0bb2e5d100271c11957cc0a753246acbc91f29a20c40cbd4c560731e324ed069",
|
||||||
|
"kind": 30168,
|
||||||
|
"pubkey": "f767d6a03639aa0f9c0fd671d496086a0fcd86d958ea31f0789c9b27daf66d70",
|
||||||
|
"sig": "d4b725fff0811e64b05616b3320a291ee698d2dbb0f5ef6a9706ed9944aef38f48449916e9598b7a190f54def5c6141e625712d118550ef10da1ef26442f5f72",
|
||||||
|
"tags": [
|
||||||
|
["d", "bestBreakfast"],
|
||||||
|
["name", "This is the title of your form! Tap to edit."],
|
||||||
|
["field", "egtD6v", "option", "What is the best breakfast?", "[[\"2KJ6h4\",\"Omelette\"],[\"1m3a5q\",\"Pancakes\"]]", "{\"renderElement\":\"radioButton\"}"
|
||||||
|
]
|
||||||
|
["v", "fb740690af9329e25b0a3c1f6ce6a24c4ff98dcba56d3579381ee340ea0350d4"],
|
||||||
|
["v", "6b557be286b13d7a85b3823c630050db043c9a28bf606aa49c65b3db0c3208b6"]
|
||||||
|
]
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Private forms editable by a group.
|
|
||||||
|
|
||||||
The rest of the mechanism remains same as in public forms editable by a group except that the
|
|
||||||
form fields should be placed in the `.content` key, encrypted by a `view-key`, which is shared in the 3rd index of the key tag for the viewers.
|
|
||||||
|
|
||||||
## Querying Form Template & Responses
|
## Querying Form Template & Responses
|
||||||
|
|
||||||
form template maybe filtered using the form author's pubkey and the d-tag as follows
|
form template maybe filtered using the form author's pubkey and the d-tag as follows
|
||||||
|
@ -167,3 +239,5 @@ const filter: Filter = {
|
||||||
};
|
};
|
||||||
if (allowedPubkeys) filter.authors = allowedPubkeys;
|
if (allowedPubkeys) filter.authors = allowedPubkeys;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Polls responses need to be queried by authors mentioned in the forms v-tag
|
||||||
|
|
Loading…
Reference in New Issue
Block a user