upgrade everything (except redis, it is dumb)

This commit is contained in:
Evert Prants 2022-08-17 22:48:20 +03:00
parent a21a2257db
commit ded40a2514
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
24 changed files with 4256 additions and 4296 deletions

View File

@ -3,7 +3,7 @@ module.exports = {
parserOptions: { parserOptions: {
project: 'tsconfig.json', project: 'tsconfig.json',
sourceType: 'module', sourceType: 'module',
tsconfigRootDir: __dirname tsconfigRootDir: __dirname,
}, },
plugins: ['@typescript-eslint/eslint-plugin'], plugins: ['@typescript-eslint/eslint-plugin'],
extends: [ extends: [
@ -21,5 +21,15 @@ module.exports = {
'@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-explicit-any': 'off',
'sort-imports': [
'warning',
{
ignoreCase: false,
ignoreDeclarationSort: false,
ignoreMemberSort: false,
memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
allowSeparatedGroups: false,
},
],
}, },
}; };

View File

@ -1,4 +1,4 @@
{ {
"singleQuote": true, "singleQuote": true,
"trailingComma": "all" "trailingComma": "all"
} }

8234
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -24,11 +24,11 @@
}, },
"dependencies": { "dependencies": {
"@icynet/oauth2-provider": "git+ssh://git@gitlab.icynet.eu:IcyNetwork/oauth2-provider.git", "@icynet/oauth2-provider": "git+ssh://git@gitlab.icynet.eu:IcyNetwork/oauth2-provider.git",
"@nestjs/common": "^8.0.0", "@nestjs/common": "^9.0.11",
"@nestjs/core": "^8.0.0", "@nestjs/core": "^9.0.11",
"@nestjs/platform-express": "^8.0.0", "@nestjs/platform-express": "^9.0.11",
"@nestjs/serve-static": "^2.2.2", "@nestjs/serve-static": "^3.0.0",
"@nestjs/throttler": "^2.0.1", "@nestjs/throttler": "^3.0.0",
"bcrypt": "^5.0.1", "bcrypt": "^5.0.1",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.13.2", "class-validator": "^0.13.2",
@ -36,67 +36,69 @@
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"cropperjs": "^1.5.12", "cropperjs": "^1.5.12",
"csrf": "^3.1.0", "csrf": "^3.1.0",
"dotenv": "^16.0.0", "dotenv": "^16.0.1",
"express-session": "^1.17.2", "express-session": "^1.17.3",
"image-size": "^1.0.1", "image-size": "^1.0.2",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"marked": "^4.0.18",
"mime-types": "^2.1.35", "mime-types": "^2.1.35",
"multer": "^1.4.4", "multer": "^1.4.4",
"mysql2": "^2.3.3", "mysql2": "^2.3.3",
"nodemailer": "^6.7.2", "nodemailer": "^6.7.8",
"otplib": "^12.0.1", "otplib": "^12.0.1",
"pug": "^3.0.2", "pug": "^3.0.2",
"qrcode": "^1.5.0", "qrcode": "^1.5.1",
"redis": "^3.1.2", "redis": "^3.1.2",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rxjs": "^7.2.0", "rxjs": "^7.5.6",
"toml": "^3.0.0", "toml": "^3.0.0",
"typeorm": "^0.2.45", "typeorm": "^0.3.7",
"uuid": "^8.3.2" "uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/preset-env": "^7.16.11", "@babel/preset-env": "^7.18.10",
"@babel/preset-typescript": "^7.16.7", "@babel/preset-typescript": "^7.18.6",
"@nestjs/cli": "^8.0.0", "@nestjs/cli": "^9.0.0",
"@nestjs/schematics": "^8.0.0", "@nestjs/schematics": "^9.0.1",
"@nestjs/testing": "^8.0.0", "@nestjs/testing": "^9.0.11",
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/connect-redis": "^0.0.18", "@types/connect-redis": "^0.0.18",
"@types/cookie-parser": "^1.4.3", "@types/cookie-parser": "^1.4.3",
"@types/express": "^4.17.13", "@types/express": "^4.17.13",
"@types/express-session": "^1.17.4", "@types/express-session": "^1.17.5",
"@types/jest": "27.4.1", "@types/jest": "28.1.7",
"@types/jsonwebtoken": "^8.5.8", "@types/jsonwebtoken": "^8.5.8",
"@types/marked": "^4.0.4",
"@types/mime-types": "^2.1.1", "@types/mime-types": "^2.1.1",
"@types/multer": "^1.4.7", "@types/multer": "^1.4.7",
"@types/node": "^16.0.0", "@types/node": "^18.7.6",
"@types/nodemailer": "^6.4.4", "@types/nodemailer": "^6.4.5",
"@types/qrcode": "^1.4.2", "@types/qrcode": "^1.4.3",
"@types/supertest": "^2.0.11", "@types/supertest": "^2.0.12",
"@types/uuid": "^8.3.4", "@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/eslint-plugin": "^5.33.1",
"@typescript-eslint/parser": "^5.0.0", "@typescript-eslint/parser": "^5.33.1",
"babel-loader": "^8.2.3", "babel-loader": "^8.2.5",
"css-loader": "^6.7.1", "css-loader": "^6.7.1",
"eslint": "^8.0.1", "eslint": "^8.22.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.2.1",
"jest": "^27.2.5", "jest": "^28.1.3",
"mini-css-extract-plugin": "^2.6.0", "mini-css-extract-plugin": "^2.6.1",
"prettier": "^2.3.2", "prettier": "^2.7.1",
"sass": "^1.49.9", "sass": "^1.54.4",
"sass-loader": "^12.6.0", "sass-loader": "^13.0.2",
"source-map-support": "^0.5.20", "source-map-support": "^0.5.21",
"supertest": "^6.1.3", "supertest": "^6.2.4",
"text-loader": "^0.0.1", "text-loader": "^0.0.1",
"ts-jest": "^27.0.3", "ts-jest": "^28.0.8",
"ts-loader": "^9.2.3", "ts-loader": "^9.3.1",
"ts-node": "^10.0.0", "ts-node": "^10.9.1",
"tsconfig-paths": "^3.10.1", "tsconfig-paths": "^4.1.0",
"typescript": "^4.3.5", "typescript": "^4.7.4",
"webpack": "^5.70.0", "webpack": "^5.74.0",
"webpack-cli": "^4.9.2" "webpack-cli": "^4.10.0"
}, },
"jest": { "jest": {
"moduleFileExtensions": [ "moduleFileExtensions": [

View File

@ -2,11 +2,12 @@ import * as toml from 'toml';
import { resolve } from 'path'; import { resolve } from 'path';
import { readFile } from 'fs/promises'; import { readFile } from 'fs/promises';
import { Configuration } from './config.interfaces'; import { Configuration } from './config.interfaces';
import { Provider } from '@nestjs/common';
const CONFIG_ENV = process.env.NODE_ENV === 'production' ? 'prod' : 'dev'; const CONFIG_ENV = process.env.NODE_ENV === 'production' ? 'prod' : 'dev';
const CONFIG_FILENAME = process.env.CONFIG || `config.${CONFIG_ENV}.toml`; const CONFIG_FILENAME = process.env.CONFIG || `config.${CONFIG_ENV}.toml`;
export const configProviders = [ export const configProviders: Provider<any>[] = [
{ {
provide: 'CONFIG_PATH', provide: 'CONFIG_PATH',
useValue: resolve(__dirname, '..', '..', '..', CONFIG_FILENAME), useValue: resolve(__dirname, '..', '..', '..', CONFIG_FILENAME),

View File

@ -1,7 +1,8 @@
import { join } from 'path'; import { join } from 'path';
import { readFile } from 'fs/promises'; import { readFile } from 'fs/promises';
import { Provider } from '@nestjs/common';
export const jwtProviders = [ export const jwtProviders: Provider<any>[] = [
{ {
provide: 'PRIVATE_PATH', provide: 'PRIVATE_PATH',
useValue: join(__dirname, '..', '..', '..', 'private'), useValue: join(__dirname, '..', '..', '..', 'private'),

View File

@ -1,7 +1,8 @@
import { Provider } from '@nestjs/common';
import { ConfigurationService } from 'src/modules/config/config.service'; import { ConfigurationService } from 'src/modules/config/config.service';
import { ConnectionOptions, createConnection } from 'typeorm'; import { ConnectionOptions, createConnection } from 'typeorm';
export const databaseProviders = [ export const databaseProviders: Provider<any>[] = [
{ {
provide: 'DATABASE_CONNECTION', provide: 'DATABASE_CONNECTION',
useFactory: async (config: ConfigurationService) => { useFactory: async (config: ConfigurationService) => {

View File

@ -0,0 +1,40 @@
import {
Column,
CreateDateColumn,
Entity,
ManyToOne,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import { User } from '../user/user.entity';
@Entity()
export class Document {
@PrimaryGeneratedColumn()
id: number;
@Column({ type: 'text', nullable: false })
title: string;
@Column({ type: 'text', nullable: false })
slug: string;
@Column({ type: 'text', nullable: false })
body: string;
@CreateDateColumn({
type: 'timestamp',
default: () => 'CURRENT_TIMESTAMP(6)',
})
public created_at: Date;
@UpdateDateColumn({
type: 'timestamp',
default: () => 'CURRENT_TIMESTAMP(6)',
onUpdate: 'CURRENT_TIMESTAMP(6)',
})
public updated_at: Date;
@ManyToOne(() => User)
author: User;
}

View File

@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { UtilityModule } from 'src/modules/utility/utility.module';
import { DatabaseModule } from '../database/database.module';
import { documentProviders } from './document.providers';
import { DocumentService } from './document.service';
@Module({
imports: [DatabaseModule, UtilityModule],
providers: [...documentProviders, DocumentService],
exports: [DocumentService],
})
export class DocumentModule {}

View File

@ -0,0 +1,17 @@
import { Provider } from '@nestjs/common';
import { join } from 'path';
import { Connection } from 'typeorm';
import { Document } from './document.entity';
export const documentProviders: Provider<any>[] = [
{
provide: 'DOCUMENT_CACHE',
useValue: join(process.cwd(), '.cache'),
},
{
provide: 'DOCUMENT_REPOSITORY',
useFactory: (connection: Connection) => connection.getRepository(Document),
inject: ['DATABASE_CONNECTION'],
},
];

View File

@ -0,0 +1,62 @@
import { Inject, Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { Document } from './document.entity';
import { TokenService } from 'src/modules/utility/services/token.service';
import { marked } from 'marked';
@Injectable()
export class DocumentService {
constructor(
@Inject('DOCUMENT_CACHE')
private documentStorage: string,
@Inject('DOCUMENT_REPOSITORY')
private documentRepository: Repository<Document>,
private tokenService: TokenService,
) {}
public slugify(text: string): string {
return text
.toString()
.normalize('NFD') // split an accented letter in the base letter and the accent
.replace(/[\u0300-\u036f]/g, '') // remove all previously split accents
.toLowerCase()
.trim()
.replace(/\s+/g, '-')
.replace(/[^\w\-]+/g, '')
.replace(/\-\-+/g, '-');
}
public async render(input: string): Promise<string> {
return new Promise((resolve, reject) => {
marked.parse(input, (err, result) => {
if (err) {
return reject(err);
}
resolve(result);
});
});
}
public async getDocumentBySlug(
slug: string,
): Promise<Document & { html: string }> {
const doc = await this.documentRepository.findOne({ where: { slug } });
const html = await this.render(doc.body);
return {
...doc,
html,
};
}
public async getDocumentByID(
id: number,
): Promise<Document & { html: string }> {
const doc = await this.documentRepository.findOne({ where: { id } });
const html = await this.render(doc.body);
return {
...doc,
html,
};
}
}

View File

@ -1,8 +1,9 @@
import { Provider } from '@nestjs/common';
import * as nodemailer from 'nodemailer'; import * as nodemailer from 'nodemailer';
import { SMTPConfiguration } from 'src/modules/config/config.interfaces'; import { SMTPConfiguration } from 'src/modules/config/config.interfaces';
import { ConfigurationService } from 'src/modules/config/config.service'; import { ConfigurationService } from 'src/modules/config/config.service';
export const emailProviders = [ export const emailProviders: Provider<any>[] = [
{ {
provide: 'EMAIL_TRANSPORT', provide: 'EMAIL_TRANSPORT',
useFactory: async (config: ConfigurationService) => useFactory: async (config: ConfigurationService) =>

View File

@ -1,9 +1,10 @@
import { Provider } from '@nestjs/common';
import { Connection } from 'typeorm'; import { Connection } from 'typeorm';
import { OAuth2ClientAuthorization } from './oauth2-client-authorization.entity'; import { OAuth2ClientAuthorization } from './oauth2-client-authorization.entity';
import { OAuth2ClientURL } from './oauth2-client-url.entity'; import { OAuth2ClientURL } from './oauth2-client-url.entity';
import { OAuth2Client } from './oauth2-client.entity'; import { OAuth2Client } from './oauth2-client.entity';
export const clientProviders = [ export const clientProviders: Provider<any>[] = [
{ {
provide: 'CLIENT_REPOSITORY', provide: 'CLIENT_REPOSITORY',
useFactory: (connection: Connection) => useFactory: (connection: Connection) =>

View File

@ -115,15 +115,15 @@ export class OAuth2ClientService {
let client: OAuth2Client; let client: OAuth2Client;
if (typeof id === 'string') { if (typeof id === 'string') {
client = await this.clientRepository.findOne( client = await this.clientRepository.findOne({
{ client_id: id }, where: { client_id: id },
{ relations: ['urls', 'picture'] }, relations: ['urls', 'picture'],
); });
} else { } else {
client = await this.clientRepository.findOne( client = await this.clientRepository.findOne({
{ id }, where: { id },
{ relations: ['urls', 'picture'] }, relations: ['urls', 'picture'],
); });
} }
return client; return client;
@ -143,13 +143,13 @@ export class OAuth2ClientService {
} }
public async checkRedirectURI(id: string, url: string): Promise<boolean> { public async checkRedirectURI(id: string, url: string): Promise<boolean> {
return !!(await this.clientUrlRepository.findOne( return !!(await this.clientUrlRepository.findOne({
{ where: {
client: { client_id: id }, client: { client_id: id },
url, url,
type: OAuth2ClientURLType.REDIRECT_URI, type: OAuth2ClientURLType.REDIRECT_URI,
}, },
{ relations: ['client'] }, relations: ['client'],
)); }));
} }
} }

View File

@ -1,7 +1,8 @@
import { Provider } from '@nestjs/common';
import { Connection } from 'typeorm'; import { Connection } from 'typeorm';
import { OAuth2Token } from './oauth2-token.entity'; import { OAuth2Token } from './oauth2-token.entity';
export const tokenProviders = [ export const tokenProviders: Provider<any>[] = [
{ {
provide: 'TOKEN_REPOSITORY', provide: 'TOKEN_REPOSITORY',
useFactory: (connection: Connection) => useFactory: (connection: Connection) =>

View File

@ -36,13 +36,13 @@ export class OAuth2TokenService {
token: string, token: string,
type: OAuth2TokenType, type: OAuth2TokenType,
): Promise<OAuth2Token> { ): Promise<OAuth2Token> {
return this.tokenRepository.findOne( return this.tokenRepository.findOne({
{ where: {
token, token,
type, type,
}, },
{ relations: ['client', 'user'] }, relations: ['client', 'user'],
); });
} }
public async fetchByUserIdClientId( public async fetchByUserIdClientId(

View File

@ -1,7 +1,8 @@
import { Provider } from '@nestjs/common';
import { Connection } from 'typeorm'; import { Connection } from 'typeorm';
import { Privilege } from './privilege.entity'; import { Privilege } from './privilege.entity';
export const privilegeProviders = [ export const privilegeProviders: Provider<any>[] = [
{ {
provide: 'PRIVILEGE_REPOSITORY', provide: 'PRIVILEGE_REPOSITORY',
useFactory: (connection: Connection) => connection.getRepository(Privilege), useFactory: (connection: Connection) => connection.getRepository(Privilege),

View File

@ -1,7 +1,8 @@
import { Provider } from '@nestjs/common';
import { Connection } from 'typeorm'; import { Connection } from 'typeorm';
import { Upload } from './upload.entity'; import { Upload } from './upload.entity';
export const uploadProviders = [ export const uploadProviders: Provider<any>[] = [
{ {
provide: 'UPLOAD_REPOSITORY', provide: 'UPLOAD_REPOSITORY',
useFactory: (connection: Connection) => connection.getRepository(Upload), useFactory: (connection: Connection) => connection.getRepository(Upload),

View File

@ -1,7 +1,8 @@
import { Provider } from '@nestjs/common';
import { Connection } from 'typeorm'; import { Connection } from 'typeorm';
import { UserToken } from './user-token.entity'; import { UserToken } from './user-token.entity';
export const userTokenProviders = [ export const userTokenProviders: Provider<any>[] = [
{ {
provide: 'USER_TOKEN_REPOSITORY', provide: 'USER_TOKEN_REPOSITORY',
useFactory: (connection: Connection) => connection.getRepository(UserToken), useFactory: (connection: Connection) => connection.getRepository(UserToken),

View File

@ -27,13 +27,13 @@ export class UserTokenService {
} }
public async get(token: string, type: UserTokenType): Promise<UserToken> { public async get(token: string, type: UserTokenType): Promise<UserToken> {
const foundOne = await this.userTokenRepository.findOne( const foundOne = await this.userTokenRepository.findOne({
{ where: {
token, token,
type, type,
}, },
{ relations: ['user'] }, relations: ['user'],
); });
if (!foundOne) { if (!foundOne) {
return null; return null;

View File

@ -33,8 +33,7 @@ export class UserTOTPService {
*/ */
public async getUserTOTP(user: User): Promise<UserToken> { public async getUserTOTP(user: User): Promise<UserToken> {
return this.userTokenRepository.findOne({ return this.userTokenRepository.findOne({
user, where: { user, type: UserTokenType.TOTP },
type: UserTokenType.TOTP,
}); });
} }

View File

@ -1,7 +1,8 @@
import { Provider } from '@nestjs/common';
import { Connection } from 'typeorm'; import { Connection } from 'typeorm';
import { User } from './user.entity'; import { User } from './user.entity';
export const userProviders = [ export const userProviders: Provider<any>[] = [
{ {
provide: 'USER_REPOSITORY', provide: 'USER_REPOSITORY',
useFactory: (connection: Connection) => connection.getRepository(User), useFactory: (connection: Connection) => connection.getRepository(User),

View File

@ -29,7 +29,7 @@ export class UserService {
return null; return null;
} }
return this.userRepository.findOne({ id }, { relations }); return this.userRepository.findOne({ where: { id }, relations });
} }
public async getByUUID(uuid: string, relations?: string[]): Promise<User> { public async getByUUID(uuid: string, relations?: string[]): Promise<User> {
@ -37,7 +37,7 @@ export class UserService {
return null; return null;
} }
return this.userRepository.findOne({ uuid }, { relations }); return this.userRepository.findOne({ where: { uuid }, relations });
} }
public async getByEmail(email: string, relations?: string[]): Promise<User> { public async getByEmail(email: string, relations?: string[]): Promise<User> {
@ -45,7 +45,7 @@ export class UserService {
return null; return null;
} }
return this.userRepository.findOne({ email }, { relations }); return this.userRepository.findOne({ where: { email }, relations });
} }
public async getByUsername( public async getByUsername(
@ -56,7 +56,7 @@ export class UserService {
return null; return null;
} }
return this.userRepository.findOne({ username }, { relations }); return this.userRepository.findOne({ where: { username }, relations });
} }
public async get( public async get(

View File

@ -29,6 +29,10 @@ export class TokenService {
return crypto.randomBytes(256 / 8).toString('hex'); return crypto.randomBytes(256 / 8).toString('hex');
} }
public insecureHash(input: string): string {
return crypto.createHash('md5').update(input).digest('hex');
}
public createUUID(): string { public createUUID(): string {
return v4(); return v4();
} }