@lenne.tech/nest-server 8.6.23 → 8.6.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.env.js +4 -1
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/decorators/restricted.decorator.d.ts +1 -0
- package/dist/core/common/decorators/restricted.decorator.js +68 -57
- package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
- package/dist/core/common/enums/role.enum.d.ts +2 -0
- package/dist/core/common/enums/role.enum.js +2 -0
- package/dist/core/common/enums/role.enum.js.map +1 -1
- package/dist/core/common/helpers/input.helper.d.ts +1 -0
- package/dist/core/common/helpers/input.helper.js +10 -2
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/helpers/model.helper.d.ts +6 -2
- package/dist/core/common/helpers/model.helper.js +14 -6
- package/dist/core/common/helpers/model.helper.js.map +1 -1
- package/dist/core/common/helpers/service.helper.d.ts +1 -0
- package/dist/core/common/helpers/service.helper.js +36 -7
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +1 -0
- package/dist/core/common/services/core-cron-jobs.service.js +2 -2
- package/dist/core/common/services/core-cron-jobs.service.js.map +1 -1
- package/dist/core/common/services/module.service.js +3 -3
- package/dist/core/common/services/module.service.js.map +1 -1
- package/dist/core/common/types/plain-object.type.d.ts +3 -0
- package/dist/core/common/types/plain-object.type.js +3 -0
- package/dist/core/common/types/plain-object.type.js.map +1 -0
- package/dist/core/modules/auth/guards/roles.guard.js +4 -1
- package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
- package/dist/core/modules/auth/services/core-auth.service.js +3 -1
- package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
- package/dist/core/modules/file/core-file-info.model.d.ts +1 -1
- package/dist/core/modules/file/core-file-info.model.js +4 -0
- package/dist/core/modules/file/core-file-info.model.js.map +1 -1
- package/dist/core/modules/user/core-user.service.js +3 -0
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/server/common/services/cron-jobs.service.js +1 -1
- package/dist/server/common/services/cron-jobs.service.js.map +1 -1
- package/dist/server/modules/auth/auth.service.js +21 -4
- package/dist/server/modules/auth/auth.service.js.map +1 -1
- package/dist/server/modules/file/file.controller.js +1 -1
- package/dist/server/modules/file/file.controller.js.map +1 -1
- package/dist/server/modules/file/file.resolver.js +1 -0
- package/dist/server/modules/file/file.resolver.js.map +1 -1
- package/dist/server/modules/user/user.model.d.ts +3 -3
- package/dist/server/modules/user/user.model.js +5 -7
- package/dist/server/modules/user/user.model.js.map +1 -1
- package/dist/server/modules/user/user.module.js +2 -0
- package/dist/server/modules/user/user.module.js.map +1 -1
- package/dist/server/modules/user/user.resolver.js +5 -0
- package/dist/server/modules/user/user.resolver.js.map +1 -1
- package/dist/server/modules/user/user.service.js +1 -1
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/test/test.helper.js +4 -4
- package/dist/test/test.helper.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/src/config.env.ts +4 -1
- package/src/core/common/decorators/restricted.decorator.ts +95 -75
- package/src/core/common/enums/role.enum.ts +34 -6
- package/src/core/common/helpers/context.helper.ts +2 -2
- package/src/core/common/helpers/input.helper.ts +17 -0
- package/src/core/common/helpers/model.helper.ts +20 -6
- package/src/core/common/helpers/service.helper.ts +45 -9
- package/src/core/common/interfaces/server-options.interface.ts +7 -0
- package/src/core/common/services/core-cron-jobs.service.ts +2 -2
- package/src/core/common/services/module.service.ts +5 -5
- package/src/core/common/types/plain-object.type.ts +5 -0
- package/src/core/common/types/remove-methods.type.ts +1 -0
- package/src/core/modules/auth/guards/roles.guard.ts +7 -2
- package/src/core/modules/auth/services/core-auth.service.ts +9 -1
- package/src/core/modules/file/core-file-info.model.ts +11 -1
- package/src/core/modules/user/core-user.service.ts +6 -0
- package/src/index.ts +1 -0
- package/src/server/common/services/cron-jobs.service.ts +1 -1
- package/src/server/modules/auth/auth.service.ts +13 -6
- package/src/server/modules/file/file.controller.ts +1 -1
- package/src/server/modules/file/file.resolver.ts +1 -0
- package/src/server/modules/user/user.model.ts +6 -5
- package/src/server/modules/user/user.module.ts +2 -0
- package/src/server/modules/user/user.resolver.ts +5 -0
- package/src/server/modules/user/user.service.ts +1 -1
- package/src/test/test.helper.ts +6 -6
|
@@ -32,6 +32,11 @@ export class RolesGuard extends AuthGuard('jwt') {
|
|
|
32
32
|
: reflectorRoles[0]
|
|
33
33
|
: reflectorRoles[1];
|
|
34
34
|
|
|
35
|
+
// Check if locked
|
|
36
|
+
if (roles && roles.includes(RoleEnum.S_NO_ONE)) {
|
|
37
|
+
throw new UnauthorizedException('No access');
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
// Check roles
|
|
36
41
|
if (!roles || !roles.some((value) => !!value)) {
|
|
37
42
|
return user;
|
|
@@ -42,8 +47,8 @@ export class RolesGuard extends AuthGuard('jwt') {
|
|
|
42
47
|
// Get args
|
|
43
48
|
const args: any = GqlExecutionContext.create(context).getArgs();
|
|
44
49
|
|
|
45
|
-
// Check special user
|
|
46
|
-
if (user && roles.includes(RoleEnum.S_USER)) {
|
|
50
|
+
// Check special user roles (user is logged in or access is free for any)
|
|
51
|
+
if ((user && roles.includes(RoleEnum.S_USER)) || roles.includes(RoleEnum.S_EVERYONE)) {
|
|
47
52
|
return user;
|
|
48
53
|
}
|
|
49
54
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
|
2
2
|
import { JwtService } from '@nestjs/jwt';
|
|
3
3
|
import * as bcrypt from 'bcrypt';
|
|
4
|
+
import { sha256 } from 'js-sha256';
|
|
4
5
|
import { merge } from '../../../common/helpers/config.helper';
|
|
5
6
|
import { ServiceOptions } from '../../../common/interfaces/service-options.interface';
|
|
6
7
|
import { ICoreAuthUser } from '../interfaces/core-auth-user.interface';
|
|
@@ -23,10 +24,17 @@ export class CoreAuthService {
|
|
|
23
24
|
serviceOptions?: ServiceOptions
|
|
24
25
|
): Promise<{ token: string; user: ICoreAuthUser }> {
|
|
25
26
|
serviceOptions = merge(serviceOptions || {}, { prepareOutput: null });
|
|
27
|
+
|
|
28
|
+
// Get user
|
|
26
29
|
const user = await this.userService.getViaEmail(email, serviceOptions);
|
|
27
|
-
if (
|
|
30
|
+
if (
|
|
31
|
+
!user ||
|
|
32
|
+
!((await bcrypt.compare(password, user.password)) || (await bcrypt.compare(sha256(password), user.password)))
|
|
33
|
+
) {
|
|
28
34
|
throw new UnauthorizedException();
|
|
29
35
|
}
|
|
36
|
+
|
|
37
|
+
// Return JWT
|
|
30
38
|
const payload: JwtPayload = { email: user.email };
|
|
31
39
|
return {
|
|
32
40
|
token: this.jwtService.sign(payload),
|
|
@@ -8,7 +8,17 @@ import { CoreModel } from '../../common/models/core-model.model';
|
|
|
8
8
|
*/
|
|
9
9
|
@ObjectType({ description: 'Information about file' })
|
|
10
10
|
export class CoreFileInfo extends CoreModel {
|
|
11
|
-
|
|
11
|
+
// ===========================================================================
|
|
12
|
+
// Getter
|
|
13
|
+
// ===========================================================================
|
|
14
|
+
|
|
15
|
+
get _id() {
|
|
16
|
+
return new Types.ObjectId(this.id);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ===========================================================================
|
|
20
|
+
// Properties
|
|
21
|
+
// ===========================================================================
|
|
12
22
|
|
|
13
23
|
@Field(() => String, { description: 'ID of the file' })
|
|
14
24
|
id: string = undefined;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { BadRequestException, NotFoundException, UnprocessableEntityException } from '@nestjs/common';
|
|
2
2
|
import * as bcrypt from 'bcrypt';
|
|
3
3
|
import * as crypto from 'crypto';
|
|
4
|
+
import { sha256 } from 'js-sha256';
|
|
4
5
|
import { Document, Model } from 'mongoose';
|
|
6
|
+
import envConfig from '../../../config.env';
|
|
5
7
|
import { merge } from '../../common/helpers/config.helper';
|
|
6
8
|
import { assignPlain } from '../../common/helpers/input.helper';
|
|
7
9
|
import { ServiceOptions } from '../../common/interfaces/service-options.interface';
|
|
@@ -128,6 +130,10 @@ export abstract class CoreUserService<
|
|
|
128
130
|
|
|
129
131
|
return this.process(
|
|
130
132
|
async () => {
|
|
133
|
+
// Check if the password was transmitted encrypted
|
|
134
|
+
// If not, the password is encrypted to enable future encrypted and unencrypted transmissions
|
|
135
|
+
newPassword = !envConfig.sha256 || /^[a-f0-9]{64}$/i.test(newPassword) ? newPassword : sha256(newPassword);
|
|
136
|
+
|
|
131
137
|
// Update and return user
|
|
132
138
|
return await assignPlain(dbObject, {
|
|
133
139
|
password: await bcrypt.hash(newPassword, 10),
|
package/src/index.ts
CHANGED
|
@@ -62,6 +62,7 @@ export * from './core/common/types/field-selection.type';
|
|
|
62
62
|
export * from './core/common/types/ids.type';
|
|
63
63
|
export * from './core/common/types/maybe-promise.type';
|
|
64
64
|
export * from './core/common/types/plain-input.type';
|
|
65
|
+
export * from './core/common/types/plain-object.type';
|
|
65
66
|
export * from './core/common/types/remove-methods.type';
|
|
66
67
|
export * from './core/common/types/require-only-one.type';
|
|
67
68
|
export * from './core/common/types/required-at-least-one.type';
|
|
@@ -21,7 +21,7 @@ export class CronJobs extends CoreCronJobs {
|
|
|
21
21
|
// ===================================================================================================================
|
|
22
22
|
|
|
23
23
|
protected async sayHello() {
|
|
24
|
-
console.
|
|
24
|
+
console.info('Hello :)');
|
|
25
25
|
await new Promise<void>((resolve) => {
|
|
26
26
|
setTimeout(() => resolve(), 30000);
|
|
27
27
|
});
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
|
2
2
|
import { JwtService } from '@nestjs/jwt';
|
|
3
3
|
import * as bcrypt from 'bcrypt';
|
|
4
|
+
import { sha256 } from 'js-sha256';
|
|
4
5
|
import envConfig from '../../../config.env';
|
|
6
|
+
import { Roles } from '../../../core/common/decorators/roles.decorator';
|
|
7
|
+
import { RoleEnum } from '../../../core/common/enums/role.enum';
|
|
5
8
|
import { prepareServiceOptions } from '../../../core/common/helpers/service.helper';
|
|
6
9
|
import { ServiceOptions } from '../../../core/common/interfaces/service-options.interface';
|
|
7
10
|
import { EmailService } from '../../../core/common/services/email.service';
|
|
@@ -12,6 +15,7 @@ import { AuthSignInInput } from './inputs/auth-sign-in.input';
|
|
|
12
15
|
import { AuthSignUpInput } from './inputs/auth-sign-up.input';
|
|
13
16
|
|
|
14
17
|
@Injectable()
|
|
18
|
+
@Roles(RoleEnum.ADMIN)
|
|
15
19
|
export class AuthService {
|
|
16
20
|
constructor(
|
|
17
21
|
protected readonly jwtService: JwtService,
|
|
@@ -22,6 +26,7 @@ export class AuthService {
|
|
|
22
26
|
/**
|
|
23
27
|
* Sign in for user
|
|
24
28
|
*/
|
|
29
|
+
@Roles(RoleEnum.S_EVERYONE)
|
|
25
30
|
async signIn(input: AuthSignInInput, serviceOptions?: ServiceOptions): Promise<Auth> {
|
|
26
31
|
// Prepare service options
|
|
27
32
|
const serviceOptionsForUserService = prepareServiceOptions(serviceOptions, {
|
|
@@ -34,12 +39,13 @@ export class AuthService {
|
|
|
34
39
|
|
|
35
40
|
// Get and check user
|
|
36
41
|
const user = await this.userService.getViaEmail(input.email, serviceOptionsForUserService);
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
if (
|
|
43
|
+
!user ||
|
|
44
|
+
!(
|
|
45
|
+
(await bcrypt.compare(input.password, user.password)) ||
|
|
46
|
+
(await bcrypt.compare(sha256(input.password), user.password))
|
|
47
|
+
)
|
|
48
|
+
) {
|
|
43
49
|
throw new UnauthorizedException();
|
|
44
50
|
}
|
|
45
51
|
|
|
@@ -54,6 +60,7 @@ export class AuthService {
|
|
|
54
60
|
/**
|
|
55
61
|
* Register a new user Account
|
|
56
62
|
*/
|
|
63
|
+
@Roles(RoleEnum.S_EVERYONE)
|
|
57
64
|
async signUp(input: AuthSignUpInput, serviceOptions?: ServiceOptions): Promise<Auth> {
|
|
58
65
|
// Prepare service options
|
|
59
66
|
const serviceOptionsForUserService = prepareServiceOptions(serviceOptions, {
|
|
@@ -42,6 +42,6 @@ export class FileController extends CoreFileController {
|
|
|
42
42
|
})
|
|
43
43
|
)
|
|
44
44
|
uploadFiles(@UploadedFiles() files, @Body() fields: any) {
|
|
45
|
-
console.
|
|
45
|
+
console.info('Saved file info', JSON.stringify({ files, fields }, null, 2));
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Field, ObjectType } from '@nestjs/graphql';
|
|
2
2
|
import { Prop, Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
|
|
3
|
-
import { Document, Schema
|
|
4
|
-
import { mapClasses } from '../../../core/common/helpers/model.helper';
|
|
3
|
+
import { Document, Schema } from 'mongoose';
|
|
5
4
|
import { CoreUserModel } from '../../../core/modules/user/core-user.model';
|
|
6
5
|
import { PersistenceModel } from '../../common/models/persistence.model';
|
|
7
6
|
|
|
@@ -34,7 +33,7 @@ export class User extends CoreUserModel implements PersistenceModel {
|
|
|
34
33
|
nullable: true,
|
|
35
34
|
})
|
|
36
35
|
@Prop({ type: Schema.Types.ObjectId, ref: 'User' })
|
|
37
|
-
createdBy:
|
|
36
|
+
createdBy: string = undefined;
|
|
38
37
|
|
|
39
38
|
/**
|
|
40
39
|
* ID of the user who updated the object
|
|
@@ -46,7 +45,7 @@ export class User extends CoreUserModel implements PersistenceModel {
|
|
|
46
45
|
nullable: true,
|
|
47
46
|
})
|
|
48
47
|
@Prop({ type: Schema.Types.ObjectId, ref: 'User' })
|
|
49
|
-
updatedBy:
|
|
48
|
+
updatedBy: string = undefined;
|
|
50
49
|
|
|
51
50
|
// ===================================================================================================================
|
|
52
51
|
// Methods
|
|
@@ -66,7 +65,9 @@ export class User extends CoreUserModel implements PersistenceModel {
|
|
|
66
65
|
*/
|
|
67
66
|
map(input) {
|
|
68
67
|
super.map(input);
|
|
69
|
-
|
|
68
|
+
// There is nothing to map yet. Non-primitive variables should always be mapped.
|
|
69
|
+
// If something comes up, you can use `mapClasses` / `mapClassesAsync` from ModelHelper.
|
|
70
|
+
return this;
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
|
|
@@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
|
|
|
2
2
|
import { MongooseModule } from '@nestjs/mongoose';
|
|
3
3
|
import { PubSub } from 'graphql-subscriptions';
|
|
4
4
|
import { JSON } from '../../../core/common/scalars/json.scalar';
|
|
5
|
+
import { ConfigService } from '../../../core/common/services/config.service';
|
|
5
6
|
import { AvatarController } from './avatar.controller';
|
|
6
7
|
import { User, UserSchema } from './user.model';
|
|
7
8
|
import { UserResolver } from './user.resolver';
|
|
@@ -16,6 +17,7 @@ import { UserService } from './user.service';
|
|
|
16
17
|
providers: [
|
|
17
18
|
JSON,
|
|
18
19
|
UserResolver,
|
|
20
|
+
ConfigService,
|
|
19
21
|
UserService,
|
|
20
22
|
{
|
|
21
23
|
provide: 'USER_CLASS',
|
|
@@ -15,6 +15,7 @@ import { UserService } from './user.service';
|
|
|
15
15
|
* Resolver to process with user data
|
|
16
16
|
*/
|
|
17
17
|
@Resolver(() => User)
|
|
18
|
+
@Roles(RoleEnum.ADMIN)
|
|
18
19
|
export class UserResolver {
|
|
19
20
|
/**
|
|
20
21
|
* Import services
|
|
@@ -53,6 +54,7 @@ export class UserResolver {
|
|
|
53
54
|
/**
|
|
54
55
|
* Get verified state of user with token
|
|
55
56
|
*/
|
|
57
|
+
@Roles(RoleEnum.S_EVERYONE)
|
|
56
58
|
@Query(() => Boolean, { description: 'Get verified state of user with token' })
|
|
57
59
|
async getVerifiedState(@Args('token') token: string) {
|
|
58
60
|
return await this.userService.getVerifiedState(token);
|
|
@@ -61,6 +63,7 @@ export class UserResolver {
|
|
|
61
63
|
/**
|
|
62
64
|
* Request new password for user with email
|
|
63
65
|
*/
|
|
66
|
+
@Roles(RoleEnum.S_EVERYONE)
|
|
64
67
|
@Query(() => Boolean, { description: 'Request new password for user with email' })
|
|
65
68
|
async requestPasswordResetMail(@Args('email') email: string): Promise<boolean> {
|
|
66
69
|
return !!(await this.userService.sendPasswordResetMail(email));
|
|
@@ -103,6 +106,7 @@ export class UserResolver {
|
|
|
103
106
|
/**
|
|
104
107
|
* Set new password for user with token
|
|
105
108
|
*/
|
|
109
|
+
@Roles(RoleEnum.S_EVERYONE)
|
|
106
110
|
@Mutation(() => Boolean, { description: 'Set new password for user with token' })
|
|
107
111
|
async resetPassword(@Args('token') token: string, @Args('password') password: string): Promise<boolean> {
|
|
108
112
|
return !!(await this.userService.resetPassword(token, password));
|
|
@@ -131,6 +135,7 @@ export class UserResolver {
|
|
|
131
135
|
/**
|
|
132
136
|
* Verify user with email
|
|
133
137
|
*/
|
|
138
|
+
@Roles(RoleEnum.S_EVERYONE)
|
|
134
139
|
@Mutation(() => Boolean, { description: 'Verify user with email' })
|
|
135
140
|
async verifyUser(@Args('token') token: string): Promise<boolean> {
|
|
136
141
|
return !!(await this.userService.verify(token));
|
|
@@ -98,7 +98,7 @@ export class UserService extends CoreUserService<User, UserInput, UserCreateInpu
|
|
|
98
98
|
if (user.avatar) {
|
|
99
99
|
fs.unlink(envConfig.staticAssets.path + '/avatars/' + user.avatar, (err) => {
|
|
100
100
|
if (err) {
|
|
101
|
-
console.
|
|
101
|
+
console.error(err);
|
|
102
102
|
}
|
|
103
103
|
});
|
|
104
104
|
}
|
package/src/test/test.helper.ts
CHANGED
|
@@ -91,7 +91,7 @@ export interface TestGraphQLOptions {
|
|
|
91
91
|
countOfSubscriptionMessages?: number;
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
*
|
|
94
|
+
* Output information in the console
|
|
95
95
|
*/
|
|
96
96
|
log?: boolean;
|
|
97
97
|
|
|
@@ -444,7 +444,7 @@ export class TestHelper {
|
|
|
444
444
|
//
|
|
445
445
|
// // Log response
|
|
446
446
|
// if (log) {
|
|
447
|
-
// console.
|
|
447
|
+
// console.info(response);
|
|
448
448
|
// }
|
|
449
449
|
//
|
|
450
450
|
// // Check data
|
|
@@ -468,7 +468,7 @@ export class TestHelper {
|
|
|
468
468
|
|
|
469
469
|
// Response
|
|
470
470
|
if (log) {
|
|
471
|
-
console.
|
|
471
|
+
console.info(requestConfig);
|
|
472
472
|
}
|
|
473
473
|
const response = await (variables ? request : request.send(requestConfig.payload));
|
|
474
474
|
return this.processResponse(response, statusCode, log, logError);
|
|
@@ -528,7 +528,7 @@ export class TestHelper {
|
|
|
528
528
|
processResponse(response, statusCode, log, logError) {
|
|
529
529
|
// Log response
|
|
530
530
|
if (log) {
|
|
531
|
-
console.
|
|
531
|
+
console.info('Response', JSON.stringify(response, null, 2));
|
|
532
532
|
}
|
|
533
533
|
|
|
534
534
|
// Log error
|
|
@@ -565,14 +565,14 @@ export class TestHelper {
|
|
|
565
565
|
|
|
566
566
|
// Init client
|
|
567
567
|
if (options.log) {
|
|
568
|
-
console.
|
|
568
|
+
console.info('Subscription query', JSON.stringify(query, null, 2));
|
|
569
569
|
}
|
|
570
570
|
const client = createClient({ url: this.subscriptionUrl, connectionParams, webSocketImpl: ws });
|
|
571
571
|
const messages: any[] = [];
|
|
572
572
|
let unsubscribe: () => void;
|
|
573
573
|
const onNext = (message) => {
|
|
574
574
|
if (options.log) {
|
|
575
|
-
console.
|
|
575
|
+
console.info('Subscription message', JSON.stringify(message, null, 2));
|
|
576
576
|
}
|
|
577
577
|
messages.push(message?.data?.[graphql.name]);
|
|
578
578
|
if (messages.length <= options.countOfSubscriptionMessages) {
|