forked from athenekilta/ilmomasiina
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #123 from Tietokilta/feat/initial-admin-creation
Initial admin creation wizard and some user management rework
- Loading branch information
Showing
36 changed files
with
473 additions
and
221 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,10 +26,6 @@ ANONYMIZE_AFTER_DAYS=180 | |
DELETION_GRACE_PERIOD_DAYS=14 | ||
|
||
|
||
# Whether or not new admin accounts can be added. REMEMBER TO DISABLE AFTER SETUP. | ||
# This is disabled by default so that new users know of this variable. | ||
ADMIN_REGISTRATION_ALLOWED=false | ||
|
||
# Whether or not to trust X-Forwarded-For headers for remote IP. Set to true IF | ||
# AND ONLY IF running behind a proxy that sets this header. | ||
TRUST_PROXY=false | ||
|
@@ -125,6 +121,7 @@ BRANDING_FOOTER_GDPR_TEXT=Tietosuoja | |
BRANDING_FOOTER_GDPR_LINK=http://example.com/privacy | ||
BRANDING_FOOTER_HOME_TEXT=Example.com | ||
BRANDING_FOOTER_HOME_LINK=http://example.com | ||
BRANDING_LOGIN_PLACEHOLDER_EMAIL=[email protected] | ||
|
||
# Email strings | ||
BRANDING_MAIL_FOOTER_TEXT=Rakkaudella, Tietskarijengi & Athene | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ env: | |
branding_footer_gdpr_link: 'https://tietokilta.fi/kilta/hallinto/viralliset-asiat/rekisteriselosteet/' | ||
branding_footer_home_text: 'Tietokilta.fi' | ||
branding_footer_home_link: 'https://tietokilta.fi' | ||
branding_login_placeholder_email: '[email protected]' | ||
|
||
on: | ||
push: | ||
|
@@ -72,6 +73,7 @@ jobs: | |
BRANDING_FOOTER_GDPR_LINK=${{ env.branding_footer_gdpr_link }} | ||
BRANDING_FOOTER_HOME_TEXT=${{ env.branding_footer_home_text }} | ||
BRANDING_FOOTER_HOME_LINK=${{ env.branding_footer_home_link }} | ||
BRANDING_LOGIN_PLACEHOLDER_EMAIL=${{ env.branding_login_placeholder_email }} | ||
# This is disabled on forks since you'll most likely need to modify it anyway for your usage | ||
deploy: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ services: | |
- BRANDING_FOOTER_GDPR_LINK=https://tietokilta.fi/kilta/hallinto/viralliset-asiat/rekisteriselosteet/ | ||
- BRANDING_FOOTER_HOME_TEXT=Tietokilta.fi | ||
- BRANDING_FOOTER_HOME_LINK=https://tietokilta.fi | ||
- [email protected] | ||
restart: always | ||
depends_on: | ||
- database | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,6 +55,7 @@ docker build \ | |
--build-arg BRANDING_FOOTER_GDPR_LINK='https://example.com' \ | ||
--build-arg BRANDING_FOOTER_HOME_TEXT='Kotisivu' \ | ||
--build-arg BRANDING_FOOTER_HOME_LINK='https://example.com' \ | ||
--build-arg BRANDING_LOGIN_PLACEHOLDER_EMAIL='[email protected]' \ | ||
-t ilmomasiina . | ||
``` | ||
|
||
|
@@ -254,7 +255,6 @@ B-tier App Service Plans have been tried and at least B1 doesn't seem to handle | |
- `DB_PASSWORD` = password of PostgreSQL user | ||
- `DB_DATABASE` = name of PostgreSQL database | ||
- `DB_SSL` = `true` (required with Azure's default config) | ||
- `ADMIN_REGISTRATION_ALLOWED` = `true` for initial setup (see [_Creating the first admin user_](#creating-the-first-admin-user)) | ||
- `NEW_EDIT_TOKEN_SECRET` = secure random string (see [_Generating secrets_](#generating-secrets)) | ||
- `FEATHERS_AUTH_SECRET` = secure random string (see [_Generating secrets_](#generating-secrets)) | ||
- `MAIL_FROM` = "From" email for system messages | ||
|
@@ -263,7 +263,6 @@ B-tier App Service Plans have been tried and at least B1 doesn't seem to handle | |
- `BRANDING_MAIL_FOOTER_TEXT` and `BRANDING_MAIL_FOOTER_LINK` (may be empty) | ||
7. Access the app at `https://{your-app-name}.azurewebsites.net/`. | ||
- If something is broken, check the *Log stream* page or read logs via `https://{your-app-name}.scm.azurewebsites.net/`. | ||
8. On first run, follow the instructions in [_Creating the first admin user_](#creating-the-first-admin-user). | ||
### Docker Compose | ||
|
@@ -275,7 +274,6 @@ You can use Docker Compose to run both a database and production container local | |
3. **Optional:** Make [customizations](#customization) in other files if necessary. | ||
4. Run `docker-compose -f docker-compose.prod.yml up` manually or e.g. via `systemd`. | ||
5. Access the app at <http://localhost:8000>. | ||
6. On first run, follow the instructions in [_Creating the first admin user_](#creating-the-first-admin-user). | ||
|
||
### Docker (manual) | ||
|
||
|
@@ -295,7 +293,6 @@ If you don't want to use Docker Compose, or already have a database, you can run | |
- Customized image, built in CI or uploaded by you: `ghcr.io/yourorg/ilmomasiina:latest` (example) | ||
- Locally built image: `ilmomasiina` (what was after `-t` in `docker build`) | ||
4. Access the app at <http://localhost:3000>. | ||
5. On first run, follow the instructions in [_Creating the first admin user_](#creating-the-first-admin-user). | ||
### Running without Docker | ||
|
@@ -312,24 +309,6 @@ You can also set up a production deployment without Docker. **This method is not | |
node packages/ilmomasiina-backend/dist/bin/server.js | ||
``` | ||
7. Access the app at <http://localhost:3000>. | ||
8. On first run, follow the instructions in [_Creating the first admin user_](#creating-the-first-admin-user). | ||
### Creating the first admin user | ||
By default, only logged-in admin users can create new admin users using the `/admin` endpoint. | ||
To create the first user on a new system, admin registration needs to be allowed. | ||
Allow admin registration temporarily by adding the env variable `ADMIN_REGISTRATION_ALLOWED=true`. | ||
Now, create a new user with POST request to `/api/users`. For example, using `curl`: | ||
``` | ||
curl 'http://localhost:3000/api/users' \ | ||
-H 'Content-Type: application/json' \ | ||
--data '{ "email": "[email protected]", "password": "password123" }' | ||
``` | ||
:warning: **Important**: After creating the first user, disallow admin user creation by | ||
removing the env variable and restarting Ilmomasiina. | ||
### Reverse proxy | ||
|
@@ -416,7 +395,6 @@ Currently Prettier is not used in the project, so here is a recommended `.vscode | |
- Alternatively, you can use `pnpm run --filter=@tietokilta/ilmomasiina-frontend start` | ||
(and similar for the backend). | ||
6. Access the app at <http://localhost:3000>. | ||
7. On first run, follow the instructions in [_Creating the first admin user_](#creating-the-first-admin-user). | ||
### Docker Compose | ||
|
@@ -428,7 +406,6 @@ pre-configured PostgreSQL server, so an external database server is not required | |
2. Go to the repository root and run `docker-compose up`. This builds the dev container and starts the frontend and | ||
backend servers in parallel. | ||
3. Access the app at <http://localhost:3000>. | ||
4. On first run, follow the instructions in [_Creating the first admin user_](#creating-the-first-admin-user). | ||
Due to how the dev Docker is set up, you will still need to rebuild the development image if you change the | ||
dependencies, package.json or ESLint configs. You'll also need Node.js and pnpm installed locally to do that. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
packages/ilmomasiina-backend/src/authentication/adminPasswordAuth.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
packages/ilmomasiina-backend/src/routes/admin/users/createInitialUser.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* eslint-disable max-classes-per-file */ | ||
import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; | ||
import { Transaction } from 'sequelize'; | ||
|
||
import { AdminLoginResponse, ErrorCode, UserCreateSchema } from '@tietokilta/ilmomasiina-models'; | ||
import AdminAuthSession from '../../../authentication/adminAuthSession'; | ||
import AdminPasswordAuth from '../../../authentication/adminPasswordAuth'; | ||
import { User } from '../../../models/user'; | ||
import CustomError from '../../../util/customError'; | ||
import { createUser } from './inviteUser'; | ||
|
||
export class InitialSetupNeeded extends CustomError { | ||
constructor(message: string) { | ||
super(418, ErrorCode.INITIAL_SETUP_NEEDED, message); | ||
} | ||
} | ||
|
||
export class InitialSetupAlreadyDone extends CustomError { | ||
constructor(message: string) { | ||
super(409, ErrorCode.INITIAL_SETUP_ALREADY_DONE, message); | ||
} | ||
} | ||
|
||
export async function isInitialSetupDone(transaction?: Transaction) { | ||
return await User.count({ transaction }) > 0; | ||
} | ||
|
||
/** | ||
* Creates a new (admin) user and logs them in | ||
* | ||
* Supposed to be used only for initial user creation. | ||
* For additional users, use {@link inviteUser} instead. | ||
*/ | ||
export default function createInitialUser(session: AdminAuthSession) { | ||
return async function handler( | ||
this: FastifyInstance<any, any, any, any, any>, | ||
request: FastifyRequest<{ Body: UserCreateSchema }>, | ||
reply: FastifyReply, | ||
): Promise<AdminLoginResponse> { | ||
AdminPasswordAuth.validateNewPassword(request.body.password); | ||
|
||
const user = await User.sequelize!.transaction(async (transaction) => { | ||
if (await isInitialSetupDone(transaction)) { | ||
throw new InitialSetupAlreadyDone('The initial admin user has already been created.'); | ||
} | ||
return createUser(request.body, request.logEvent, transaction); | ||
}); | ||
|
||
const accessToken = session.createSession({ user: user.id, email: user.email }); | ||
|
||
// Stop raising errors on requests to event list | ||
this.initialSetupDone = true; | ||
|
||
reply.status(201); | ||
return { accessToken }; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.