From c278f6d78b7199525f2c68ea79a0fc8801041573 Mon Sep 17 00:00:00 2001 From: David Mehren Date: Sun, 12 Mar 2023 21:42:39 +0100 Subject: [PATCH] docs: Split up 2.0.md and rename to dev_notes.md Signed-off-by: David Mehren --- docs/content/dev/2.0.md | 60 ------------------------ docs/content/dev/design_docs/api_auth.md | 25 ++++++++++ docs/content/dev/design_docs/notes.md | 13 ++++- docs/content/dev/dev_notes.md | 29 ++++++++++++ docs/mkdocs.yml | 2 +- 5 files changed, 67 insertions(+), 62 deletions(-) delete mode 100644 docs/content/dev/2.0.md create mode 100644 docs/content/dev/dev_notes.md diff --git a/docs/content/dev/2.0.md b/docs/content/dev/2.0.md deleted file mode 100644 index 70f8f639c..000000000 --- a/docs/content/dev/2.0.md +++ /dev/null @@ -1,60 +0,0 @@ -# 2.0 Development Notes -This document collects notes and decisions taken during the development of HedgeDoc 2.0. -It should be converted to a properly structured documentation, but having unstructured docs -is better than having no docs. - -## Supported databases -We intend to officially support and test these databases: -- SQLite (for development and smaller instances) -- PostgreSQL -- MariaDB - -## Special Groups -The software provides two special groups which have no explicit users: -- `everyone` (Describing that everyone who wants to access a note can do if it is enabled in the config.) -- `loggedIn` (Describing all users which are logged in) - -## Deleting notes and revisions -- The owner of a note may delete it. - - By default, this also removes all revisions and all files that were uploaded to that note. - - The owner may choose to skip deleting associated uploads, leaving them without a note. - - The frontend should show a list of all uploads that will be affected - and provide a method of skipping deletion. -- The owner of a note may delete all revisions. This effectively purges the edit - history of a note. - -## Entity `create` methods - -Because we need to have empty constructors in our entity classes for TypeORM to work, the actual constructor is a separate `create` method. These methods should adhere to these guidelines: - -- Only require the non-optional properties of the corresponding entity -- Have no optional parameters -- Have no lists which can be empty (so probably most of them) -- Should either return a complete and fully useable instance or return a Pick/Omit type. -- Exceptions to these rules are allowed, if they are mentioned in the method documentation - -## Auth tokens for the public API -The public API uses bearer tokens for authentication. - -When a new token is requested via the private API, the backend generates a 64 bytes-long secret of -cryptographically secure data and returns it as a base64url-encoded string, along with an identifier. -That string can then be used by clients as a bearer token. - -A SHA-512 hash of the secret is stored in the database. To validate tokens, the backend computes the hash of the provided -secret and checks it against the stored hash for the provided identifier. - -### Choosing a hash function -Unfortunately, there does not seem to be any explicit documentation about our exact use-case. -Most docs describe classic password-saving scenarios and recommend bcrypt, scrypt or argon2. -These hashing functions are slow to stop brute-force or dictionary attacks, which would expose the original, -user-provided password, that may have been reused across multiple services. - -We have a very different scenario: -Our API tokens are 64 bytes of cryptographically strong pseudorandom data. -Brute-force or dictionary attacks are therefore virtually impossible, and tokens are not reused across multiple services. -We therefore need to only guard against one scenario: -An attacker gains read-only access to the database. Saving only hashes in the database prevents the attacker -from authenticating themselves as a user. The hash-function does not need to be very slow, -as the randomness of the original token prevents inverting the hash. The function actually needs to be reasonably fast, -as the hash must be computed on every request to the public API. -SHA-512 (or alternatively SHA3) fits this use-case. diff --git a/docs/content/dev/design_docs/api_auth.md b/docs/content/dev/design_docs/api_auth.md index 34dab132c..7dfb812f4 100644 --- a/docs/content/dev/design_docs/api_auth.md +++ b/docs/content/dev/design_docs/api_auth.md @@ -6,6 +6,31 @@ All requests to the public API require authentication using a [bearer token](htt This token can be generated using the profile page in the frontend (which in turn uses the private API to generate the token). +### Token generation + +When a new token is requested via the private API, the backend generates a 64 bytes-long secret of +cryptographically secure data and returns it as a base64url-encoded string, along with an identifier. +That string can then be used by clients as a bearer token. + +A SHA-512 hash of the secret is stored in the database. To validate tokens, the backend computes the hash of the provided +secret and checks it against the stored hash for the provided identifier. + +#### Choosing a hash function +Unfortunately, there does not seem to be any explicit documentation about our exact use-case. +Most docs describe classic password-saving scenarios and recommend bcrypt, scrypt or argon2. +These hashing functions are slow to stop brute-force or dictionary attacks, which would expose the original, +user-provided password, that may have been reused across multiple services. + +We have a very different scenario: +Our API tokens are 64 bytes of cryptographically strong pseudorandom data. +Brute-force or dictionary attacks are therefore virtually impossible, and tokens are not reused across multiple services. +We therefore need to only guard against one scenario: +An attacker gains read-only access to the database. Saving only hashes in the database prevents the attacker +from authenticating themselves as a user. The hash-function does not need to be very slow, +as the randomness of the original token prevents inverting the hash. The function actually needs to be reasonably fast, +as the hash must be computed on every request to the public API. +SHA-512 (or alternatively SHA3) fits this use-case. + ## Private API The private API uses a session cookie to authenticate the user. diff --git a/docs/content/dev/design_docs/notes.md b/docs/content/dev/design_docs/notes.md index 1b82b9ddd..fc253f871 100644 --- a/docs/content/dev/design_docs/notes.md +++ b/docs/content/dev/design_docs/notes.md @@ -54,7 +54,18 @@ All mentioned fields are extracted from the note content by the backend on save `version` specifies if a note is an old HedgeDoc 1 note, or a new HedgeDoc 2 note. This is mainly used to redirect old notes form to . -### Conversion of HedgeDoc 1 notes +## Deleting Notes + +- The owner of a note may delete it. + - By default, this also removes all revisions and all files that were uploaded to that note. + - The owner may choose to skip deleting associated uploads, leaving them without a note. + - The frontend should show a list of all uploads that will be affected + and provide a method of skipping deletion. +- The owner of a note may delete all revisions. This effectively purges the edit + history of a note. + + +## Conversion of HedgeDoc 1 notes First we want to define some terms of the HedgeDoc 1 notes: diff --git a/docs/content/dev/dev_notes.md b/docs/content/dev/dev_notes.md new file mode 100644 index 000000000..ad1fab897 --- /dev/null +++ b/docs/content/dev/dev_notes.md @@ -0,0 +1,29 @@ +# Development Notes +This document collects notes and decisions taken during the development of HedgeDoc 2.0. +It should be converted to a properly structured documentation, but having unstructured docs +is better than having no docs. + +## Supported databases +We intend to officially support and test these databases: + +- SQLite (for development and smaller instances) +- PostgreSQL +- MariaDB + +## Special Groups +The software provides two special groups which have no explicit users: + +- `everyone` (Describing that everyone who wants to access a note can do if it is enabled in the config.) +- `loggedIn` (Describing all users which are logged in) + +## Entity `create` methods + +Because we need to have empty constructors in our entity classes for TypeORM to work, the actual constructor is a separate `create` method. These methods should adhere to these guidelines: + +- Only require the non-optional properties of the corresponding entity +- Have no optional parameters +- Have no lists which can be empty (so probably most of them) +- Should either return a complete and fully useable instance or return a Pick/Omit type. +- Exceptions to these rules are allowed, if they are mentioned in the method documentation + + diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 772942e6c..1fea1a606 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -22,7 +22,7 @@ nav: - Development: - Getting Started: dev/getting-started.md - Frontend: dev/setup/frontend.md - - '2.0 Development': dev/2.0.md + - Development Notes: dev/dev_notes.md - Design Documents: - API Authentication: dev/design_docs/api_auth.md - Configuration: dev/design_docs/config.md