Add debug logging to `saveFile` method and throw the proper errors when problems with the mime type are encountered
Signed-off-by: David Mehren <git@herrmehren.de>
We use `fs.unlink` instead of `fs.rm`, as the latter is only available in the fsPromises API since Node 14.14
Signed-off-by: David Mehren <git@herrmehren.de>
This service is responsible for operations regarding uploaded media. It should perform save, get and delete operations with the configured backend.
The service also checks, if the mime type of the uploaded media is allowed.
Signed-off-by: David Mehren <git@herrmehren.de>
It turned out that saving the file extension in a separate field is not necessary. Instead, the extension is saved in the complete filename in the `id` field.
Signed-off-by: David Mehren <git@herrmehren.de>
This backend stores uploaded media into files on the local filesystem.
This commit also adds a `BackendType` enum, which can be used to distinguish different media backends.
Signed-off-by: David Mehren <git@herrmehren.de>
which puts the markdown text directly to a variable in the route function.
Content-type of the http request is checked to be text/markdown because we dealing with markdown. Technically by now there can be any content which can be encoded. There could be features in the software which do not work properly if the text can't be parsed as markdown.
Signed-off-by: Yannick Bungers <git@innay.de>
ConsoleLoggerService is based on the default Nest LoggerService, but adds the ability to give context about the function that is logging something. It also removes the `[Nest]` string and the PID at the beginning of each log line.
NestConsoleLoggerService is a wrapper around ConsoleLoggerService and makes it possible to use our implementation as a default Nest LoggerService
Signed-off-by: David Mehren <git@herrmehren.de>
It might be handy to have access to the original `Note` after creating one, so the creation and conversion to a `NoteDto` is now split.
Signed-off-by: David Mehren <git@herrmehren.de>
The precision of sqlites datetime() timestamp is only one second (see https://www.sqlite.org/lang_datefunc.html). Therefore we could not order revisions of one note that were created in the same second. To remedy this, the primary key was changed to a monotonically increasing number, which solves the ordering problem.
Signed-off-by: David Mehren <git@herrmehren.de>
This commit also introduces the `getNoteDtoByIdOrAlias` method, that converts a `Note` entity to a `NoteDto`
Signed-off-by: David Mehren <git@herrmehren.de>
The `create()` function did not initialize all arrays, which caused them to be `undefined` instead of empty.
Signed-off-by: David Mehren <git@herrmehren.de>
TypeORM does not like having application code in the constructor (https://github.com/typeorm/typeorm/issues/1772#issuecomment-514787854), therefore that is moved into a new `create() static method. Additionally, the constructor is now `private`, which enforces the use of the new method.
Signed-off-by: David Mehren <git@herrmehren.de>
NestJS does not support content-types other than application/json.
Therefore we need to directly access the request object to get the raw body content.
Signed-off-by: David Mehren <git@herrmehren.de>
This commit implements the User entity according to the database schema and adds the Identity and AuthToken entities.
Signed-off-by: David Mehren <git@herrmehren.de>
This entity implements the Session interface from connect-typeorm, which we will later use to store session data from express-session.
Signed-off-by: David Mehren <git@herrmehren.de>
We now use the new permissions split in users and groups. Also the note now knows the colors of its authors.
Signed-off-by: David Mehren <git@herrmehren.de>
NestJS can automatically generate an OpenAPI spec by analyzing controllers and used DTOs.
This commit enables this feature. The API docs are served under /apidoc.
Signed-off-by: David Mehren <git@herrmehren.de>
This adds all controllers needed in the public API (at least as currently specified) and implements some routes under `/me`
Signed-off-by: David Mehren <git@herrmehren.de>
This contains the module, a service (which only returns mock data), a model and two DTOs for history entries.
Signed-off-by: David Mehren <git@herrmehren.de>
fix warning line 38 Missing return type on function
fix error line 47 Missing space before function parentheses
Signed-off-by: Bennet Bleßmann <bb-github@t-online.de>
Instead of using sequelize-cli and ensure migrations by shellscript,
this patch automates database migrations properly to the umzug library.
The sequelize CLI becomes a dev dependencies as it's still useful for
generating migrations.
This should eliminate the need for crude generating of database config
files and alike. Instead we utilize the pre-configured sequelize
connection that CodiMD will use anyway.
Signed-off-by: Sheogorath <sheogorath@shivering-isles.com>
dmpWorker is run as a childProcess, which is a completely separate
nodejs instance. As such, the `logger` it obtains is a separate instance
than the one in the parent. The parent reads the config file to
determine the log level, but the childProcess does not. So the log level
used in dmpWorker is always `debug`, regardless of the configuration
options.
In addition to polluting the logs, this is potentially a privacy issue,
because `dmpWorker` logs the diffs of notes at the `debug` level, which
will then enter the system logs.
This commit fixes this by making `dmpWorker` send any messages back to
the parent, who is responsible for logging. This also avoids any
potential race conditions between the two loggers writing to the same
output.
Fixes#433
Signed-off-by: Dexter Chua <dec41@srcf.net>
Our frontend requests the `/me` pathname in order to determine whether
it's logged in or not. Due to the fact that the sameSite attribute of
the session cookie was set to `strict` in a previous commit, the session
token was no longer sent along with HTTP calls initiated by JS. This is
due to the RFCs definition of "safe" HTTP calls in RFC7231.
The bug triggers the UI to show up like an unauthenticated user, even
after a successful login. In order to debug it a look into the send
cookies to the `/me` turned out to be very enlightening.
The fix this patch implements is rather simple, it replaces the sameSite
attribute to `lax` which enables the cookies for those requests again.
Some older and mobile clients were unaffected by this due to the lack of
implementations of sameSite policies.
References:
https://tools.ietf.org/html/rfc7231#section-4.2.1https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-05#section-5.3.7.1https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSitee77e7b165a
Signed-off-by: Sheogorath <sheogorath@shivering-isles.com>
We enabled the `secure` flag for various cookies in previous commits.
This caused setups behind reverse proxies to drop cookies as the nodejs
instance wasn't aware of the fact that it was able to hand out secure
commits using an insecure connection (between the codimd instance and
the reverse proxy).
This patch makes express, the webserver framework we use, aware of
proxies and this way re-enabled the handing out of cookies. Not only the
cookie monster will enjoy, but also functionality like authentication
and real-time editing will return as intended.
References:
https://www.npmjs.com/package/express-session#cookiesecure383d791a50
Signed-off-by: Sheogorath <sheogorath@shivering-isles.com>
While HSTS should take care of most of this, setting cookies to be
secure, and only applied on same site helps to improve situations where
for whatever reason, downgrade attacks are still a thing.
This patch adds the `sameSite` and `secure` to the session cookie and
this way prevent all accidents where a browser may doesn't support HSTS
or HSTS is intentionally dropped.
Reference:
https://www.npmjs.com/package/express-session#cookiesecure
Signed-off-by: Sheogorath <sheogorath@shivering-isles.com>
According to https://github.com/socketio/socket.io/issues/2276 this cookie is not used for anything. To avoid browser warnings about the sameSite attribute, we disable it here.
Signed-off-by: David Mehren <dmehren1@gmail.com>
Modern browsers do not support (or will stop supporting) sameSite: none (or no sameSite attribute) without the Secure flag. As we don't want everyone to be able to make requests with our cookies anyway, this commit sets sameSite to strict. See https://developer.mozilla.org/de/docs/Web/HTTP/Headers/Set-Cookie/SameSite
Signed-off-by: David Mehren <dmehren1@gmail.com>
Previously, upon receiving a termination signal, the process tries to
flush all changes to the database, retrying every 0.1s until it
succeeds. However, if the database is not set up properly, this always
fails, and spams the terminal/logging with the error message 10 times a
second.
If the user sends another termination signal, the handleTermSignal
function is called once again, and we get twice the number of error
messages.
This commit changes the behaviour in various ways.
(1) It lowers the retry rate to 0.5s, and aborts after 30 seconds.
(2) If the write to the database errored, the error message explains
that this is due to us flushing the final changes.
(3) We replace realtime.maintenance with realtime.state, which is an
Enum with three possible states --- Starting, Running, and Stopping.
If a termination signal is received in the starting state, the
process simply aborts because there is nothing to clean up. This is
the case when the database is misconfigured, since the application
starts up only after connecting to the databse. If it is in the
Stopping state, the handleTermSignal function returns because
another instance of handleTermSignal is already running.
Fixes#408
Signed-off-by: Dexter Chua <dec41@srcf.net>
This makes it more convenient to modify the permission model, both for
future modifications and for custom installations.
This changes the `owner` property of NoteSession to `ownerId`, which is
a more accurate description anyway.
Signed-off-by: Dexter Chua <dec41@srcf.net>
OAuth2 allows the user to only consent to a subset of the scopes
requested. Previously, the Generic Oauth2 implementation assumes that
the `username`, `email` and `displayName` attributes are supplied, and
may crash if they are not defined.
This commit allows for `email` and `displayName` to not be defined,
either through the user refusing consent or the OAuth2 configuration
not asking for them in the first place (by not setting
`userProfile*Attr`).
If `email` is not provided, the `emails` property is simply left empty.
If `displayName` is not provided, it is left undefined, and CodiMD uses
the `username` whenever the `displayName` is expected.
This does not deal with the case where `username` is not provided. Since
usernames are not unique in CodiMD, it is possible to deal with this by
setting a dummy username. This can be added in a future commit if
desired.
Fixes#406
Signed-off-by: Dexter Chua <dalcde@yahoo.com.hk>
This allows configuring the group and mode of the unix socket after it
has been created to allow reverse proxies to access it. Fixes#317.
I decided to call `chown` and `chgrp` directly to change the owner and
group (the former will almost definitely not be called; only root can
chown a file to another user, and you are not running codimd as root. It
is included for consistency).
The nodejs chown/chgrp functions only accepts uid and gid, not the names
of the user or group. The standard way to convert a group name into a gid
is the `uid-number` package. The way this package works is that
1. It spawns a new nodejs process
2. The new nodejs process calls nodejs' setgid function, which *does*
accept both the group name and gid
3. It then calls getuid to retrieve the uid of the process, and returns
it to the parent process via stdout.
While this *works*, it is hacky, and if we are spawning a process
anyway, might as well call `chgrp` directly.
This does not update the documentation because we are merging into
release/2.0.x but master reworks the configuration section of the
documentation, so there will be a conflict when we merge anyway.
Signed-off-by: Dexter Chua <dalcde@yahoo.com.hk>
The code intends to check if the note is anonymous by checking if it has
an owner. If it is anonymous, the default permission must be `freely`.
However, at this point in the code, `owner` is never populated; only
`ownerId` is. The property `owner` is automatically filled in *after*
the Note is created, but this call happens before that.
Thus, the default note permission is always `freely`, regardless of the
`defaultPermission` setting. By checking `ownerId` instead of `owner`,
the anonymity and hence default permission is correctly determined,
This is especially an issue when `allowAnonymous` is `false`, since this
would allow the user to create a note with `freely` permission when it
should not be allowed.
Signed-off-by: Dexter Chua <dalcde@yahoo.com.hk>
The OAuth2 specification RECOMMENDS setting the state to protect against
CSRF attacks. Some OAuth2 providers (e.g. ORY Hydra) refuse to
authenticate without the state set.
Signed-off-by: Dexter Chua <dalcde@yahoo.com.hk>
The previous Profile type was renamed to PassportProfile, as it is only used for profile-information from Passport plugins.
All functions relating to profile-parsing are now encapsulated in the PhotoProfile class (naming still debatable).
Signed-off-by: David Mehren <dmehren1@gmail.com>
It turns out our shiny new typed ES2015 `Map`s are not serializable to JSON. :(
Luckily, we only use strings as keys and can write a function that converts them to serializable objects!
Signed-off-by: David Mehren <dmehren1@gmail.com>
a7aaded6 started to use a Map for a users note history in various places, but didn't update the code to actually use the Map operations. This broke updating the note history.
Signed-off-by: David Mehren <dmehren1@gmail.com>
`mock-require` does not work with TypeScript, as the compiled JS expects a sub-object: `import { config } from Config` compiles to `const config_1 = require("./config")`, but the config object is now in `config_1.config`, *not* in `config_1` directly.
Therefore `mock-require` was replaced with `ts-mock-imports`, which also simplifies the code a bit.
Signed-off-by: David Mehren <dmehren1@gmail.com>