Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,10 @@ services:
# Api key is set by ./etherpad/devApiKey.txt
ETHERPAD_API_KEY: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
# the Redis config is set by the "redis" service below
REDIS_HOST: redis
REDIS_PORT: 6379
# the Mailer config is set by the "mailer" service below
MAILER_CONFIG_SMTP_HOST: mailer
MAILER_CONFIG_SMTP_PORT: 1025
MAILER_CONFIG_SMTP_USE_SSL: 'false' # only for dev purposes
MAILER_CONFIG_USERNAME: docker
MAILER_CONFIG_PASSWORD: docker
REDIS_CONNECTION: redis://redis:6379

# the Mailer config is set by the "mailer" service below
MAILER_CONNECTION: smtp://docker:docker@mailer:1025
# the Localstack config is set by the "localstack" service below
S3_FILE_ITEM_HOST: http://localstack:4566
# the Iframely config is set by the "iframely" service below
Expand Down
13 changes: 3 additions & 10 deletions .github/workflows/deploy-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,7 @@ jobs:
environment-variables: |
DB_CONNECTION_POOL_SIZE=${{ vars.DB_CONNECTION_POOL_SIZE }}
APPS_JWT_SECRET=${{ secrets.APPS_JWT_SECRET }}
APPS_PUBLISHER_ID=${{ secrets.APPS_PUBLISHER_ID }}
AUTH_TOKEN_EXPIRATION_IN_MINUTES=${{ vars.AUTH_TOKEN_EXPIRATION_IN_MINUTES }}
APPS_PUBLISHER_ID=${{ secrets.APPS_PUBLISHER_ID }}
AUTH_TOKEN_JWT_SECRET=${{ secrets.AUTH_TOKEN_JWT_SECRET }}
CLIENT_HOST=${{ vars.CLIENT_HOST }}
COOKIE_DOMAIN=${{ vars.COOKIE_DOMAIN }}
Expand Down Expand Up @@ -126,21 +125,15 @@ jobs:
LIBRARY_CLIENT_HOST=${{ vars.LIBRARY_CLIENT_HOST }}
LOG_LEVEL=${{ vars.LOG_LEVEL }}
MAILER_CONFIG_FROM_EMAIL=${{ secrets.MAILER_CONFIG_FROM_EMAIL }}
MAILER_CONFIG_PASSWORD=${{ secrets.MAILER_CONFIG_PASSWORD }}
MAILER_CONFIG_SMTP_HOST=${{ secrets.MAILER_CONFIG_SMTP_HOST }}
MAILER_CONFIG_USERNAME=${{ secrets.MAILER_CONFIG_USERNAME }}
MAILER_CONNECTION=${{ secrets.MAILER_CONNECTION }}
MEILISEARCH_MASTER_KEY=${{ secrets.MEILISEARCH_MASTER_KEY }}
MEILISEARCH_REBUILD_SECRET=${{ secrets.MEILISEARCH_REBUILD_SECRET }}
MEILISEARCH_URL=${{ secrets.MEILISEARCH_URL }}
NODE_ENV=${{ vars.NODE_ENV }}
PORT=${{ vars.PORT }}
PUBLIC_URL=${{ secrets.PUBLIC_URL }}
RECAPTCHA_SECRET_ACCESS_KEY=${{ secrets.RECAPTCHA_SECRET_ACCESS_KEY }}
REDIS_HOST=${{ secrets.REDIS_HOST }}
REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}
REDIS_PORT=${{ secrets.REDIS_PORT }}
REDIS_USERNAME=${{ secrets.REDIS_USERNAME }}
REFRESH_TOKEN_EXPIRATION_IN_MINUTES=${{ vars.REFRESH_TOKEN_EXPIRATION_IN_MINUTES }}
REDIS_CONNECTION=${{ secrets.REDIS_CONNECTION }}
REFRESH_TOKEN_JWT_SECRET=${{ secrets.REFRESH_TOKEN_JWT_SECRET }}
S3_FILE_ITEM_ACCESS_KEY_ID=${{ secrets.S3_FILE_ITEM_ACCESS_KEY_ID }}
S3_FILE_ITEM_BUCKET=${{ vars.S3_FILE_ITEM_BUCKET }}
Expand Down
13 changes: 3 additions & 10 deletions .github/workflows/deploy-stage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,7 @@ jobs:
environment-variables: |
DB_CONNECTION_POOL_SIZE=${{ vars.DB_CONNECTION_POOL_SIZE }}
APPS_JWT_SECRET=${{ secrets.APPS_JWT_SECRET }}
APPS_PUBLISHER_ID=${{ secrets.APPS_PUBLISHER_ID }}
AUTH_TOKEN_EXPIRATION_IN_MINUTES=${{ secrets.AUTH_TOKEN_EXPIRATION_IN_MINUTES }}
APPS_PUBLISHER_ID=${{ secrets.APPS_PUBLISHER_ID }}
AUTH_TOKEN_JWT_SECRET=${{ secrets.AUTH_TOKEN_JWT_SECRET }}
CLIENT_HOST=${{ vars.CLIENT_HOST }}
COOKIE_DOMAIN=${{ vars.COOKIE_DOMAIN }}
Expand Down Expand Up @@ -127,21 +126,15 @@ jobs:
LIBRARY_CLIENT_HOST=${{ vars.LIBRARY_CLIENT_HOST }}
LOG_LEVEL=${{ vars.LOG_LEVEL }}
MAILER_CONFIG_FROM_EMAIL=${{ secrets.MAILER_CONFIG_FROM_EMAIL }}
MAILER_CONFIG_PASSWORD=${{ secrets.MAILER_CONFIG_PASSWORD }}
MAILER_CONFIG_SMTP_HOST=${{ secrets.MAILER_CONFIG_SMTP_HOST }}
MAILER_CONFIG_USERNAME=${{ secrets.MAILER_CONFIG_USERNAME }}
MAILER_CONNECTION=${{ secrets.MAILER_CONNECTION }}
MEILISEARCH_MASTER_KEY=${{ secrets.MEILISEARCH_MASTER_KEY }}
MEILISEARCH_REBUILD_SECRET=${{ secrets.MEILISEARCH_REBUILD_SECRET }}
MEILISEARCH_URL=${{ secrets.MEILISEARCH_URL }}
NODE_ENV=${{ vars.NODE_ENV }}
PORT=${{ vars.PORT }}
PUBLIC_URL=${{ secrets.PUBLIC_URL }}
RECAPTCHA_SECRET_ACCESS_KEY=${{ secrets.RECAPTCHA_SECRET_ACCESS_KEY }}
REDIS_HOST=${{ secrets.REDIS_HOST }}
REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}
REDIS_PORT=${{ secrets.REDIS_PORT }}
REDIS_USERNAME=${{ secrets.REDIS_USERNAME }}
REFRESH_TOKEN_EXPIRATION_IN_MINUTES=${{ vars.REFRESH_TOKEN_EXPIRATION_IN_MINUTES }}
REDIS_CONNECTION=${{ secrets.REDIS_CONNECTION }}
REFRESH_TOKEN_JWT_SECRET=${{ secrets.REFRESH_TOKEN_JWT_SECRET }}
S3_FILE_ITEM_ACCESS_KEY_ID=${{ secrets.S3_FILE_ITEM_ACCESS_KEY_ID }}
S3_FILE_ITEM_BUCKET=${{ vars.S3_FILE_ITEM_BUCKET }}
Expand Down
7 changes: 2 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,9 @@ env:
JWT_SECRET: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
PASSWORD_RESET_JWT_SECRET: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
EMAIL_CHANGE_JWT_SECRET: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
MAILER_CONFIG_PASSWORD: password
MAILER_CONFIG_SMTP_HOST: localhost
MAILER_CONFIG_USERNAME: username
MAILER_CONNECTION: smtp://username:password@localhost:1025
RECAPTCHA_SECRET_ACCESS_KEY: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
REDIS_HOST: localhost
REDIS_PORT: 6379
REDIS_CONNECTION: 'redis://localhost:6379'
REFRESH_TOKEN_JWT_SECRET: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
S3_FILE_ITEM_ACCESS_KEY_ID: graasp-user
S3_FILE_ITEM_BUCKET: graasp
Expand Down
16 changes: 4 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,25 +132,19 @@ SECURE_SESSION_SECRET_KEY=<secret-key>
JWT_SECRET=<secret-key>
# Auth JWT secret (can use the same command as for SECURE_SESSION_SECRET_KEY)
AUTH_TOKEN_JWT_SECRET=<secret-key>
# AUTH_TOKEN_EXPIRATION_IN_MINUTES=10080
# Refresh JWT secret (can use the same command as for SECURE_SESSION_SECRET_KEY)
REFRESH_TOKEN_JWT_SECRET=<secret-key>
# REFRESH_TOKEN_EXPIRATION_IN_MINUTES=86400
# Password reset JWT secret (can use the same command as for SECURE_SESSION_SECRET_KEY)
PASSWORD_RESET_JWT_SECRET=<secret-key>
# PASSWORD_RESET_JWT_EXPIRATION_IN_MINUTES=1440
# Email change JWT secret (can use the same command as for SECURE_SESSION_SECRET_KEY)
EMAIL_CHANGE_JWT_SECRET=<secret-key>
# EMAIL_CHANGE_JWT_EXPIRATION_IN_MINUTES=1440


### Mail server configuration

# Mailer config (set by ./.devcontainer/docker-compose.yml)
# Set to random values if you don't want to use the mock mailbox at http://localhost:1080
# MAILER_CONFIG_SMTP_HOST=mailer
# MAILER_CONFIG_USERNAME=graasp
# MAILER_CONFIG_PASSWORD=graasp
# MAILER_CONNECTION=


### File storages configuration
Expand Down Expand Up @@ -201,10 +195,8 @@ GRAASPER_CREATOR_ID=<id>

# Graasp websockets
# Redis config set by ./.devcontainer/docker-compose.yml
# REDIS_HOST=redis
# REDIS_PORT=6379
# REDIS_USERNAME=
# REDIS_PASSWORD=
# redis[s]://[[username][:password]@][host][:port][/db-number]:
# REDIS_CONNECTION=

# Graasp Actions
SAVE_ACTIONS=true
Expand Down Expand Up @@ -250,7 +242,7 @@ You can also run `yarn seed` to feed the database with predefined mock data.

## Utilities

The development [docker-compose.yml](.devcontainer/docker-compose.yml) provides an instance of [mailcatcher](https://mailcatcher.me/), which emulates a SMTP server for sending e-mails. When using the email authentication flow, the mailbox web UI is accessible at [http://localhost:1080](http://localhost:1080). If you do not want to use mailcatcher, set the `MAILER_CONFIG_SMTP_HOST` variable in your `.env.development` to some random value (e.g. empty string). This will log the authentication links in the server console instead.
The development [docker-compose.yml](.devcontainer/docker-compose.yml) provides an instance of [mailcatcher](https://mailcatcher.me/), which emulates a SMTP server for sending e-mails. When using the email authentication flow, the mailbox web UI is accessible at [http://localhost:1080](http://localhost:1080). If you do not want to use mailcatcher, set the `MAILER_CONNECTION` variable in your `.env.development` to some random value (e.g. empty string). This will log the authentication links in the server console instead.
Comment thread
pyphilia marked this conversation as resolved.

The development [docker-compose.yml](.devcontainer/docker-compose.yml) provides a [static file server](https://static-web-server.net/) for serving files when using the `local` storage option (alternative to the `s3` option). This option has the added benefit of being persistent when used locally in opposition to localstack (see the [known issues section](#known-issues) for more informations). The server is available at `http://localhost:1081`.

Expand Down
8 changes: 2 additions & 6 deletions docker/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,7 @@ services:
APPS_JWT_SECRET: # replace with your own value

# the Mailer config is set by the "mailer" service below
MAILER_CONFIG_SMTP_HOST: mailer
MAILER_CONFIG_SMTP_PORT: 1025
MAILER_CONFIG_SMTP_USE_SSL: 'false' # enable if your mail server supports SSL (if using the local mailcatcher, disable SSL)
MAILER_CONFIG_USERNAME: docker
MAILER_CONFIG_PASSWORD: docker
MAILER_CONNECTION: smtp://docker:docker@mailer:1025

# H5P configuration
H5P_FILE_STORAGE_TYPE: local
Expand All @@ -80,7 +76,7 @@ services:
ETHERPAD_API_KEY: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef

# Redis
REDIS_HOST: redis
REDIS_CONNECTION: redis://redis:6379

EMBEDDED_LINK_ITEM_IFRAMELY_HREF_ORIGIN: http://iframely:8061

Expand Down
9 changes: 2 additions & 7 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { maintenancePlugin } from './services/maintenance/maintenance.controller
import MemberServiceApi from './services/member';
import tagPlugin from './services/tag/tag.controller';
import websocketsPlugin from './services/websockets/websocket.controller';
import { REDIS_HOST, REDIS_PASSWORD, REDIS_PORT, REDIS_USERNAME } from './utils/config';
import { REDIS_CONNECTION } from './utils/config';

export default async function (instance: FastifyInstance): Promise<void> {
await instance
Expand Down Expand Up @@ -48,12 +48,7 @@ export default async function (instance: FastifyInstance): Promise<void> {
prefix: '/ws',
redis: {
channelName: 'graasp-realtime-updates',
config: {
host: REDIS_HOST,
port: REDIS_PORT,
username: REDIS_USERNAME,
password: REDIS_PASSWORD,
},
connection: REDIS_CONNECTION,
},
})
.register(fp(MemberServiceApi))
Expand Down
35 changes: 4 additions & 31 deletions src/di/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,10 @@ import {
GEOLOCATION_API_KEY,
IMAGE_CLASSIFIER_API,
MAILER_CONFIG_FROM_EMAIL,
MAILER_CONFIG_PASSWORD,
MAILER_CONFIG_SMTP_HOST,
MAILER_CONFIG_SMTP_PORT,
MAILER_CONFIG_SMTP_USE_SSL,
MAILER_CONFIG_USERNAME,
MAILER_CONNECTION,
MEILISEARCH_MASTER_KEY,
MEILISEARCH_URL,
REDIS_HOST,
REDIS_PASSWORD,
REDIS_PORT,
REDIS_USERNAME,
REDIS_CONNECTION,
S3_FILE_ITEM_PLUGIN_OPTIONS,
} from '../utils/config';
import {
Expand Down Expand Up @@ -64,15 +57,7 @@ export const registerDependencies = (instance: FastifyInstance) => {
// register geolocation key for the ItemGeolocationService.
registerValue(GEOLOCATION_API_KEY_DI_KEY, GEOLOCATION_API_KEY);

registerValue(
Redis,
new Redis({
host: REDIS_HOST,
port: REDIS_PORT,
username: REDIS_USERNAME,
password: REDIS_PASSWORD,
}),
);
registerValue(Redis, new Redis(REDIS_CONNECTION));

// Register CachingService for the thumbnails urls.
registerValue(
Expand Down Expand Up @@ -131,20 +116,8 @@ export const registerDependencies = (instance: FastifyInstance) => {
registerValue(
MailerService,
new MailerService({
host: MAILER_CONFIG_SMTP_HOST,
port: MAILER_CONFIG_SMTP_PORT,
useSsl: MAILER_CONFIG_SMTP_USE_SSL,
username: MAILER_CONFIG_USERNAME,
password: MAILER_CONFIG_PASSWORD,
connection: MAILER_CONNECTION,
fromEmail: MAILER_CONFIG_FROM_EMAIL,
}),
);
// registerValue('MAIL_KEY', {
// host: MAILER_CONFIG_SMTP_HOST,
// port: MAILER_CONFIG_SMTP_PORT,
// useSsl: MAILER_CONFIG_SMTP_USE_SSL,
// username: MAILER_CONFIG_USERNAME,
// password: MAILER_CONFIG_PASSWORD,
// fromEmail: MAILER_CONFIG_FROM_EMAIL,
// });
};
13 changes: 2 additions & 11 deletions src/jobs.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
import { ConnectionOptions, Queue, Worker } from 'bullmq';

import { BaseLogger } from './logger';
import {
JOB_SCHEDULING,
REDIS_HOST,
REDIS_PASSWORD,
REDIS_PORT,
REDIS_USERNAME,
} from './utils/config';
import { JOB_SCHEDULING, REDIS_CONNECTION } from './utils/config';

const connection: ConnectionOptions = {
host: REDIS_HOST,
port: REDIS_PORT,
username: REDIS_USERNAME,
password: REDIS_PASSWORD,
url: REDIS_CONNECTION,
};

export const CRON_3AM_MONDAY = '0 3 * * 1';
Expand Down
18 changes: 3 additions & 15 deletions src/plugins/mailer/mailer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ export interface Mail {
}

export interface MailerOptions {
host: string;
port?: number;
useSsl?: boolean;
username: string;
password: string;
connection: string;
fromEmail: string;
}

Expand All @@ -24,17 +20,9 @@ export class MailerService {
private readonly fromEmail: string;
private readonly transporter: Transporter;

constructor({ host, port, useSsl, username, password, fromEmail }: MailerOptions) {
constructor({ connection, fromEmail }: MailerOptions) {
this.fromEmail = fromEmail;
this.transporter = createTransport({
host,
port: port ?? 465,
secure: useSsl ?? true,
auth: {
user: username,
pass: password,
},
});
this.transporter = createTransport(connection);
}

/**
Expand Down
12 changes: 2 additions & 10 deletions src/services/auth/plugins/password/password.controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ import { MailerService } from '../../../../plugins/mailer/mailer.service';
import { assertIsDefined } from '../../../../utils/assertions';
import {
PASSWORD_RESET_JWT_EXPIRATION_IN_MINUTES,
REDIS_HOST,
REDIS_PASSWORD,
REDIS_PORT,
REDIS_USERNAME,
REDIS_CONNECTION,
} from '../../../../utils/config';
import { assertIsMember, assertIsMemberForTest } from '../../../authentication';

Expand Down Expand Up @@ -458,12 +455,7 @@ describe('Password', () => {
// Overwrite the setex method to test the expiration
jest.spyOn(Redis.prototype, 'setex').mockImplementationOnce((key, seconds, value) => {
expect(seconds).toBe(PASSWORD_RESET_JWT_EXPIRATION_IN_MINUTES * 60);
const redis = new Redis({
host: REDIS_HOST,
port: REDIS_PORT,
username: REDIS_USERNAME,
password: REDIS_PASSWORD,
});
const redis = new Redis(REDIS_CONNECTION);
return redis.setex(key, 1, value);
});

Expand Down
5 changes: 1 addition & 4 deletions src/services/websockets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,8 @@ The plugin accepts the following options (which all have sane defaults):
await instance.register(graaspWebSockets, {
prefix: '/ws',
redis: {
connectionString: <connection-string>
config: {
host: REDIS_HOST,
port: +REDIS_PORT,
username: REDIS_USERNAME,
password: REDIS_PASSWORD,
... // any other RedisOptions property from 'ioredis'
}
channelName: 'graasp-notif',
Expand Down
12 changes: 6 additions & 6 deletions src/services/websockets/multi-instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/
import { JTDSchemaType } from 'ajv/dist/core';
import { Ajv } from 'ajv/dist/jtd';
import { Redis, RedisOptions } from 'ioredis';
import { Redis } from 'ioredis';

import { FastifyBaseLogger } from 'fastify';

Expand Down Expand Up @@ -67,8 +67,8 @@ const redisSerdes = {
};

// Helper to create a redis client instance
function createRedisClientInstance(redisConfig: RedisOptions, log?: FastifyBaseLogger): Redis {
const redis = new Redis(redisConfig);
function createRedisClientInstance(redisConnection: string, log?: FastifyBaseLogger): Redis {
const redis = new Redis(redisConnection);

redis.on('error', (err) => {
log?.error(
Expand Down Expand Up @@ -96,15 +96,15 @@ class MultiInstanceChannelsBroker {
constructor(
wsChannels: WebSocketChannels,
redisParams: {
config: RedisOptions;
connection: string;
channelName: string;
},
log?: FastifyBaseLogger,
) {
this.wsChannels = wsChannels;
this.notifChannel = redisParams.channelName;
this.sub = createRedisClientInstance(redisParams.config, log);
this.pub = createRedisClientInstance(redisParams.config, log);
this.sub = createRedisClientInstance(redisParams.connection, log);
this.pub = createRedisClientInstance(redisParams.connection, log);

this.sub.subscribe(this.notifChannel, (err, _result) => {
if (err) {
Expand Down
4 changes: 1 addition & 3 deletions src/services/websockets/test/multi-instance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,7 @@ test.skip('incorrect Redis message format', async () => {
const server = await createWsFastifyInstance(config, async (instance) => {
logInfoSpy = jest.spyOn(instance.log, 'info');
});
const pub = new Redis({
host: config.redis.config.host,
});
const pub = new Redis(config.redis.connection);
pub.publish(config.redis.channelName, JSON.stringify('Mock invalid redis message'));
await waitForExpect(() => {
expect(logInfoSpy).toHaveBeenCalledWith(
Expand Down
Loading
Loading