Add Poll Mechanism

This commit is contained in:
abhay-raizada 2024-06-13 23:58:38 +05:30
parent 694658ca46
commit 588070774a

164
101.md
View File

@ -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