Comments (14)
I have written a proposal for the protocol for the Invitations. This protocol avoids the server storing any secrets for the creation of invitations.
from torrust-index-archive.
@WarmBeer, @BelieveInBunny, @george-avn
My first protocol proposal works in a similar way as hashed passwords, the server doesn't store any passwords directly, but only a hashed image of the password (appropriately salted of-course). If the hashed-password database was public, nobody would be able to instantly log-in because to authenticate one must provide the pre-image to the hashed password i.e. (password || salt).
The limitation of this approach is that for every user-secret there needs to have an associated hashed image that is registered on the server. Meaning that the user must inform the server about any new tokens.
The naรฏve approach is to instead to store a secret on the server. To generate a new token, a secret and token iterator are hashed encrypted, i.e (hash(secret || nonce). The user then gives the token-bearer the hashed secret and the nonce. When the token-bearer supplies this to the server, the sever can hash the nonce with the stored secret and check the validity of the encrypted hashed token.
This approach allows the user to generate new tokens independently without coordination with the server. i.e. offline. The problem is that we have moved back to the original insecurity of the server holding secrets, anyone with access to the servers secret store can impersonate any token they want.
The correct approach to allow for independent token generation is to use cryptographic signatures. The users registers their public key with the server. To generate a token the user signs the token with their private key, producing a secure signature. The token-bearer bring this signed token to the server, who verifies the signature against the pre-registered public key.
This approach has none of the downfalls of the other approaches, tokens can be generated independently of the sever, and there is no secret data that is stored inside the server's databases. The problem is that is slightly harder to implement, and the tokens are a little larger. (maybe 80bytes instead of 30bytes).
I am considering to write another protocol that uses the cryptographic signature approach, as it is much more future-proof; and the allowance for independent token generation is very useful. (Another 'Invitation Server' could be set-up, and generate tokens based upon it's own policy; it would not need to communicate with any other server).
from torrust-index-archive.
@BelieveInBunny Great! I will write the signed invitation specification, until then work on the other tasks. ๐
from torrust-index-archive.
Signed Invitation Codes
This is an alternative specification for making Invitation Codes. This specification has a specific advantage on-top-of the Normal Invitation Codes: Non-Interactive Code Generation.
Non-Interactive Code Generation
No-interactive code generation allows for a user to create new invitation codes without any additional communication with the server. This would allow for example an invitation server or bot to give out codes without needing to continually connect to the Torrust Backend API.
Signed Invitations Overview
- User Generates a Private/Public Keypair.
- User Registers their Public Key with the Server.
- User Makes New Invitations by Signing an Invitation Message.
- The Server verify the signature of Signing an Invitation against the Registered Public Key for that User.
Technology Used
Using standard schnorr signatures for secp256k1. Used by Bitcoin in the recent Taproot Upgrade.
BIP340 - Schnorr Signatures for secp256k1 (The Signing Algorithm)
libsecp256k1 - C Implementation of Signing Algorithm.
rust-secp256k1 - Rust-Binding to libsecp256k1. (For Backend Signature Verification)
noble-secp256k1 - TypeScript Implementation secp256k1. (For Frontend Signature Verification)
bip-0350 - The specification for bech32m.
bech32 - TypeScript implementation of Bech32m (For Encoding the Invitation)
Specification
Introduction
Users of Torrust should easily be able to invite their friends to also use Torrust. One option, when public facing registrations have closed, is that uses are granted a certain amount of 'invitation slots' that their friends may use.
Users who invite other users should be linked, so that the Torrust Administrators can easily resolve issues when invitations have unfortunately brought unfriendly people into the community.
Power-Users may want to setup systems that allow them to automatically generate new invitations. It is convenient for these systems to run independently without need of a connection to the Torrust-Backend API.
The Torrust-Backend should not store any secrets from the users. Just like the use of appropriately implemented hashed passwords, likewise invitations should not rely on secrets held by the backend.
Backend Database
Invitations
TABLE USER
. INVITATIONS
KEY SIGNED_DIGEST
The 32-byte message hash that was signed.
VALUES:
PUBLIC_KEY
LINKUSER.INVITATION_PUBLIC_KEYS.PUBLIC_KEY
INVITATION_BEGIN
INVITATION_EXPIRY
COUNT_USES
COUNT_PENDING_USES
When an active attempt for registration is in process. When an attempt fails or times-out, this number is reduced.COUNT_MAX_USES
Total Max. Users + Pending.PERSONAL_MESSAGE
of this invitation.
Invitation Slots
TABLE USER
. INVITATION_SLOTS
KEY USER
User that was successfully registered using this invitation slot.
VALUES:
INVITATION
LINKUSER.INVITATIONS.SIGNED_DIGEST
DATE_USED
USE_COUNT
at time of registration, how many times this invitation had been used.
User Public Keys
TABLE USER
. INVITATION_PUBLIC_KEYS
KEY PUBLIC_KEY
The 32-byte Public Key.
VALUES:
DATE_REGISTERED
DATE_BEGIN
Date when this public key begins to be active. I.e. Status WAITINGDATE_EXPIRY
COUNT_USES
COUNT_PENDING_USES
The number of ongoing registration attempts now. i.e. How many people who have used valid invitations to begin the registration process, but haven't activated their accounts yet, such as still waiting for their email to confirm, etc. When an attempt fails or times-out, this number is reduced.COUNT_PENDING_USES_MAX
The Maximum Number of simultaneously registering attempts.COUNT_MAX_USES
Total Max. Users + Pending.ONGOING_REGISTRATION_COUNT
ONGOING_REGISTRATION_COUNT_MAX
STATUS
ENUMWAITING. ACTIVE. EXPIRED. MAX_REACHED. REVOKED.
User
TABLE USER
NEW_VALUES:
INVITATIONS_MAX
The maximum number of invitations.INVITATIONS
TABLEINVITATION_SLOTS_MAX
The maximum number of invitation slots.INVITATION_SLOTS
TABLEINVITATION_PUBLIC_KEYS_MAX
The maximum number of Public Keys.INVITATION_PUBLIC_KEYS_MAX_ACTIVE
The maximum number of Public Keys in Active State.INVITATION_PUBLIC_KEYS_MAX_WAITING
The maximum number of Public Keys in Waiting State.INVITATION_PUBLIC_KEYS
TABLEINVITED_BY
LINK.OPTIONALUSER
(Optional. Some users are not invited.)
Invitation Format
Datatypes:
PrivateKey.
32-byte array. Uniform Random. Generated by User.
PublicKey.
32-byte array. Derived from PrivateKey.
Signature.
64-byte array. Created by signing the invitation.
Invitation_Digest.
32-byte array. Created by the tagged_hash of the signing algorithm from the Invitation_Payload.
UserID.
8-byte array. Unique. Received from Server.
Begin.
8-byte array. 64-bit Unix Time. UTC.
Expiry.
8-byte array. 64-bit Unix Time. UTC.
Uses_Max.
4-byte array. Zero for Unlimited.
Personal_Message.
Variable-Length. 0 to Max 480-bytes. UTC-8 Encoded.
**NOTE. This field MUST be excepted properly when displayed, and stored within the JSON, and the Database.**
Invitation_Payload.
Variable-Length. Min. 8 + 8 + 8 + 4 + 0 = 20-bytes. Max. 20 + 480 = 500-bytes.
UserID || Begin || Expiry || Uses_Max || Personal_Message
Invitation.
Variable-Length. Min. 64 + 20 = 84-bytes. Max. 64 + 500 = 564-bytes.
Signature || Invitation_Payload
Encoded Formats.
Encoding using Bech32m
Encoded PrivateKey.
human-readable part: torrust_bip340_pk
separator: 1
data part: PrivateKey (32-byte)
Note, this is used for the backup-transfer of the private key used to generate new invitations.
Invitation.
human-readable part: UNIQUE_TO_NODE
separator: 1
data part: Invitation. (Variable-Length. 84-byte to 564-bytes)
The invitation is encoded and decoded by the frontend.
from torrust-index-archive.
@WarmBeer @BelieveInBunny @george-avn Please Review. ๐
from torrust-index-archive.
Hey @WarmBeer,
Sure, There are in-fact two competing proposals:
Invitation Codes (Interactive Code Generation): torrust/torrust-index#30 (comment)
Signed Invitation Codes (Non-interactive Code Generation): torrust/torrust-index#30 (comment)
The main advantage of the non-interactive code generation in the case that this software becomes very popular.
- It allows websites to make 'invitation portals' without needing to connect to the torrust-index api.
- It will also enable the possibility that users to generate invitations 'offline', maybe at a conference or something.
Overall I think that it is a cool thing to have, so "coolness factor" may be a thing. When you have public keys connected to an account, we could extend the same system to work as account-recovery or two-factor, or even implement other privacy features.
:)
Cam.
from torrust-index-archive.
Proposal for invitation specification:
- Invitations are generated by users.
- Invitations linked to the account that generated them.
- Invitation may be used a configurable number of times.
- Invitation have a validity start and finish date times.
- Upon successful registration, the new user's account is linked to the account that made the invitation
- User accounts have a configurable number of invited user slots. Once full, the invitations will stop to work.
- User accounts can revoke invitations they have previously generated.
There is NO secret data that is stored on the server for making a Invitation.
A invitation is NOT supplied by a web URL. Instead it is a prefixed code.
Data Types:
4Byte Unique User ID:
Generated By Server upon User Registration.
16Byte Invitation Secret Token:
Randomly Generated by User.
Private to Invitation. Sent to server for Verification when token is Used.
16Byte Token Salt:
Randomly Generated by Server. Returned to User In-Pre Registration of Token.
Used to stop reuse of the same `Invitation Hashed Token`
16Byte Invitation Hashed Token:
Generated by User. Registered with Server. Used by server to Verify Tokens.
Blake3 Hashed: (Invitation Secret Token || Unique User ID || Token Hashed Salt) -> 16Byte Output.
16Byte Token ID Salt:
Randomly Generated by Server. Returned to User after Registering Token.
8Byte Token ID:
Generated by Server and User.
Blake3 Hashed: (Invitation Hashed Token || Unique User ID || Token ID Salt) -> 8Byte Output.
12Byte Token Index:
Index for Token's in Server Database.
Form: Unique User ID || Token ID
8Byte Token Start Time:
Unix 64bit Time. Selected by User. Registered with Server.
8Byte Token End Time:
Unix 64bit Time. Selected by User. Registered with Server.
4Byte Maximum Use Count:
Maximum number of times this token can be used. Selected by User. Registered with Server.
4Byte Token Use Count:
Kept track by Server.
28Byte Invitation Payload:
Unique User ID || Token ID || Invitation Secret Token
Making a Token.
- User asks to Server to Start the New Invitation Token Process.
- Server Generates, Stores, and Returns
Token Salt
. - User Generates
Invitation Secret Token
and Derives theInvitation Hashed Token
. - User Registers the New Invitation Token with the Server, Sending:
Token Salt
Invitation Hashed Token
Token Start Time
Token End Time
Maximum Use Count
- Server Generates, Stores, and Returns the
Token ID Salt
. - Server Derives the
Token ID
and uses it as the index for the User's Invitation Tokens. - User Derives the
Token ID
, and formats theInvitation Payload
. - User Bech32m Encodes the
Invitation Payload
with the correct Human Readable Part.
Using a Token.
- User decodes the
Invitation Payload
from the Bech32m token. - User sends the to the server:
Unique User ID
Token ID
Invitation Secret Token
- The Server looks up the User ID, Finds the Correct Token ID, and gets the
Invitation Hashed Token
- The Server compares the computed
Invitation Hashed Token
with the version on file. - The Server accepts the token as valid if the same.
- The Server checks the associated
Token Start Time
, ยดToken End Time, and
Maximum Use Count, and
Token Use Count` - The Server checks if the user has any invitation slots left. And Locks a Slot for the Time taken to register.
- The Server allows the user to register.
Upon Successful registration the server allocates:
- The new user to the Locked Invitation Slot.
- Iterates the Associated Token's
Token Use Count
If the Registration somehow fails or has a time-out, the Server unlocks the Invitation Slot
Rust Blake3: https://docs.rs/blake3/latest/blake3/
JavaScript: https://github.com/connor4312/blake3
JavaScript Bech32m: https://github.com/bitcoinjs/bech32
A Invitation-code is encoded with: Bech32m.
It has the following form:
- Human Readable Part:
Configurable "short-name" of the tracker, such as: 'irontracker', or 'supernest' etc. - The Separator:
Standard to use the character One โ1โ
The Payload is the28Byte Invitation Payload
The Bech32m Encoding is both Encoded and Decoded on the Fronted.
from torrust-index-archive.
I have written a proposal for the protocol for the Invitations. This protocol avoids the server storing any secrets for the creation of invitations.
it is a good idea. I will help to implement it like this
from torrust-index-archive.
@BelieveInBunny I have updated the proposal to assure that a hashed token cannot be reused in multiple invitations. (using a server supplied salt).
from torrust-index-archive.
it is a bit difficult to implement but a better way to approach, I will start work on this.
should I work on this first or finish other milestone 1.1.0 first?
(e.g. #11
#49 )
from torrust-index-archive.
Noted with thanks
from torrust-index-archive.
Hey @da2ce7 ,
Thank you for the very interesting and detailed proposal. I am however a little bit ignorant of the use case of such a complicated user invitation system. Could you explain to me the benefit of generating these invitation tokens independently from a Torrust Index backend so I understand why this is needed?
from torrust-index-archive.
Hey @da2ce7 ,
I made an activity diagram of what happens when the backend receives a user registration request.
We talked about how to store pending user registrations in the database and how to clean them up. The ideas we discussed were:
1. Create a separate DB table "pending_users" and store new users in that table until they are verified (on which they will move to the "user" table). The table will also have a scheduler to automatically expire rows that didn't verify in time.
Pros:
- The "user" table only contains verified users.
Cons:
- Requires a "smart" database. If we keep using the database as purely storage without any logic, it will be easier to implement other database solutions.
2. Keep using the "emailed_verified" flag in the "users" table. The backend will then have to run a cronjob to remove users that took too long to verify their email.
Pros:
- We don't have to make changes to the current "user" table.
Cons:
- The "user" table will be contaminated with unverified accounts.
- Cronjobs always run at a certain interval and that will result into variable timeframes of being able to verify user accounts.
While working on the activity diagram, I thought of another solution:
3. Store unverified accounts in memory (with something like Redis) and only submit them to the "user" database on verification.
Pros:
- We keep all the logic of verifying accounts in the backend, which gives us more flexibility if we want to make changes to that process.
- Less querying of the database compared to the other two solutions.
Cons:
- More memory usage (~80 bytes per pending user)
Let me know what you think :)
from torrust-index-archive.
from torrust-index-archive.
Related Issues (20)
- Allow renaming categories and tags HOT 3
- Show number of torrents using a tag in the `tag` administration tab HOT 1
- Report issue button HOT 1
- Contributor Agreement (CA) HOT 7
- The frontend and backend need to be moved into their own repositories
- Readme additions and corrections HOT 2
- Workflows with errors
- README: Test and Build badge HOT 1
- Contributor agreement adaptation to Torrus from the original Nautilus Cyberneering and clean up empty lines in Readme
- Contributor Agreement - Replace one Nautilus Mention
- LICENSE - Multilicense change links to Torrust and take out the Nautilus reference
- Add manual user activation HOT 4
- User Roles/Permissions HOT 2
- Improve error messages in the UI HOT 3
- [bug] users not getting logged out when their sessions expire HOT 2
- Implement Cameron's signed invitation proposal HOT 4
- Overhall Readme File
- Make backend settings read-only HOT 1
- Scraping the DHT?
- Allow banning users HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. ๐๐๐
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google โค๏ธ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from torrust-index-archive.