@skroz/profile-api 1.0.5
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/LICENCE.md +21 -0
- package/dist/adapters/TypeOrmProfileAdapter.d.ts +13 -0
- package/dist/adapters/TypeOrmProfileAdapter.js +54 -0
- package/dist/dto/ConfirmEmailInput.d.ts +6 -0
- package/dist/dto/ConfirmEmailInput.js +27 -0
- package/dist/dto/ForgotPasswordInput.d.ts +9 -0
- package/dist/dto/ForgotPasswordInput.js +31 -0
- package/dist/dto/LoginInput.d.ts +12 -0
- package/dist/dto/LoginInput.js +31 -0
- package/dist/dto/PasswordInput.d.ts +9 -0
- package/dist/dto/PasswordInput.js +31 -0
- package/dist/dto/RecoverPasswordInput.d.ts +12 -0
- package/dist/dto/RecoverPasswordInput.js +28 -0
- package/dist/dto/RegisterInput.d.ts +16 -0
- package/dist/dto/RegisterInput.js +40 -0
- package/dist/dto/SendTokenPayload.d.ts +4 -0
- package/dist/dto/SendTokenPayload.js +27 -0
- package/dist/dto/StatusPayload.d.ts +3 -0
- package/dist/dto/StatusPayload.js +23 -0
- package/dist/dto/UpdateEmailInput.d.ts +9 -0
- package/dist/dto/UpdateEmailInput.js +31 -0
- package/dist/dto/UpdatePasswordInput.d.ts +12 -0
- package/dist/dto/UpdatePasswordInput.js +28 -0
- package/dist/dto/UpdateProfileInput.d.ts +9 -0
- package/dist/dto/UpdateProfileInput.js +31 -0
- package/dist/dto/index.d.ts +11 -0
- package/dist/dto/index.js +27 -0
- package/dist/entities/TypeOrmBaseUser.d.ts +25 -0
- package/dist/entities/TypeOrmBaseUser.js +117 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +24 -0
- package/dist/resolvers/AuthResolver.d.ts +38 -0
- package/dist/resolvers/AuthResolver.js +219 -0
- package/dist/resolvers/ProfileResolver.d.ts +24 -0
- package/dist/resolvers/ProfileResolver.js +145 -0
- package/dist/services/ProfileAuthService.d.ts +24 -0
- package/dist/services/ProfileAuthService.js +94 -0
- package/dist/services/ProfileEmailService.d.ts +15 -0
- package/dist/services/ProfileEmailService.js +105 -0
- package/dist/types/index.d.ts +98 -0
- package/dist/types/index.js +10 -0
- package/dist/validators/isTrue.d.ts +3 -0
- package/dist/validators/isTrue.js +7 -0
- package/package.json +45 -0
- package/src/adapters/TypeOrmProfileAdapter.ts +40 -0
- package/src/dto/ConfirmEmailInput.ts +12 -0
- package/src/dto/ForgotPasswordInput.ts +17 -0
- package/src/dto/LoginInput.ts +20 -0
- package/src/dto/PasswordInput.ts +17 -0
- package/src/dto/RecoverPasswordInput.ts +20 -0
- package/src/dto/RegisterInput.ts +29 -0
- package/src/dto/SendTokenPayload.ts +10 -0
- package/src/dto/StatusPayload.ts +7 -0
- package/src/dto/UpdateEmailInput.ts +17 -0
- package/src/dto/UpdatePasswordInput.ts +20 -0
- package/src/dto/UpdateProfileInput.ts +17 -0
- package/src/dto/index.ts +11 -0
- package/src/entities/TypeOrmBaseUser.ts +87 -0
- package/src/index.ts +8 -0
- package/src/resolvers/AuthResolver.ts +195 -0
- package/src/resolvers/ProfileResolver.ts +107 -0
- package/src/services/ProfileAuthService.ts +122 -0
- package/src/services/ProfileEmailService.ts +158 -0
- package/src/types/index.ts +102 -0
- package/src/validators/isTrue.ts +8 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var TypeOrmBaseUser_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.TypeOrmBaseUser = void 0;
|
|
14
|
+
const typeorm_1 = require("typeorm");
|
|
15
|
+
const type_graphql_1 = require("type-graphql");
|
|
16
|
+
let TypeOrmBaseUser = TypeOrmBaseUser_1 = class TypeOrmBaseUser extends typeorm_1.BaseEntity {
|
|
17
|
+
checkOnline(seconds) {
|
|
18
|
+
if (!this.lastSeenAt)
|
|
19
|
+
return false;
|
|
20
|
+
const filterDate = new Date();
|
|
21
|
+
filterDate.setSeconds(filterDate.getSeconds() - seconds);
|
|
22
|
+
return this.lastSeenAt > filterDate;
|
|
23
|
+
}
|
|
24
|
+
get isOnline() {
|
|
25
|
+
return this.checkOnline(TypeOrmBaseUser_1.config.isOnlineSeconds);
|
|
26
|
+
}
|
|
27
|
+
get isOnlineRecently() {
|
|
28
|
+
return this.checkOnline(TypeOrmBaseUser_1.config.isOnlineRecentlySeconds);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
exports.TypeOrmBaseUser = TypeOrmBaseUser;
|
|
32
|
+
TypeOrmBaseUser.config = {
|
|
33
|
+
isOnlineSeconds: 60,
|
|
34
|
+
isOnlineRecentlySeconds: 300,
|
|
35
|
+
};
|
|
36
|
+
__decorate([
|
|
37
|
+
(0, type_graphql_1.Field)(() => type_graphql_1.ID),
|
|
38
|
+
(0, typeorm_1.PrimaryGeneratedColumn)(),
|
|
39
|
+
__metadata("design:type", Number)
|
|
40
|
+
], TypeOrmBaseUser.prototype, "id", void 0);
|
|
41
|
+
__decorate([
|
|
42
|
+
(0, type_graphql_1.Field)(() => type_graphql_1.GraphQLTimestamp),
|
|
43
|
+
(0, typeorm_1.CreateDateColumn)({ type: 'timestamptz' }),
|
|
44
|
+
__metadata("design:type", Date)
|
|
45
|
+
], TypeOrmBaseUser.prototype, "createdAt", void 0);
|
|
46
|
+
__decorate([
|
|
47
|
+
(0, type_graphql_1.Field)(() => type_graphql_1.GraphQLTimestamp),
|
|
48
|
+
(0, typeorm_1.UpdateDateColumn)({ type: 'timestamptz' }),
|
|
49
|
+
__metadata("design:type", Date)
|
|
50
|
+
], TypeOrmBaseUser.prototype, "updatedAt", void 0);
|
|
51
|
+
__decorate([
|
|
52
|
+
(0, typeorm_1.Column)({ type: 'varchar', nullable: true, unique: true }),
|
|
53
|
+
__metadata("design:type", Object)
|
|
54
|
+
], TypeOrmBaseUser.prototype, "email", void 0);
|
|
55
|
+
__decorate([
|
|
56
|
+
(0, typeorm_1.Column)(),
|
|
57
|
+
__metadata("design:type", String)
|
|
58
|
+
], TypeOrmBaseUser.prototype, "password", void 0);
|
|
59
|
+
__decorate([
|
|
60
|
+
(0, typeorm_1.Column)({ default: false }),
|
|
61
|
+
__metadata("design:type", Boolean)
|
|
62
|
+
], TypeOrmBaseUser.prototype, "isTempPassword", void 0);
|
|
63
|
+
__decorate([
|
|
64
|
+
(0, typeorm_1.Column)({ default: false }),
|
|
65
|
+
__metadata("design:type", Boolean)
|
|
66
|
+
], TypeOrmBaseUser.prototype, "isEmailConfirmed", void 0);
|
|
67
|
+
__decorate([
|
|
68
|
+
(0, type_graphql_1.Field)(() => Boolean),
|
|
69
|
+
(0, typeorm_1.Column)({ default: true }),
|
|
70
|
+
__metadata("design:type", Boolean)
|
|
71
|
+
], TypeOrmBaseUser.prototype, "isEmailNotificationEnabled", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
(0, type_graphql_1.Field)(() => Boolean),
|
|
74
|
+
(0, typeorm_1.Column)({ default: true }),
|
|
75
|
+
__metadata("design:type", Boolean)
|
|
76
|
+
], TypeOrmBaseUser.prototype, "isTelegramNotificationEnabled", void 0);
|
|
77
|
+
__decorate([
|
|
78
|
+
(0, type_graphql_1.Field)(() => Boolean),
|
|
79
|
+
(0, typeorm_1.Column)({ default: false }),
|
|
80
|
+
__metadata("design:type", Boolean)
|
|
81
|
+
], TypeOrmBaseUser.prototype, "isBanned", void 0);
|
|
82
|
+
__decorate([
|
|
83
|
+
(0, type_graphql_1.Field)(() => Boolean),
|
|
84
|
+
(0, typeorm_1.Column)({ default: false }),
|
|
85
|
+
__metadata("design:type", Boolean)
|
|
86
|
+
], TypeOrmBaseUser.prototype, "isDeleted", void 0);
|
|
87
|
+
__decorate([
|
|
88
|
+
(0, typeorm_1.Column)({ type: 'varchar', nullable: true, unique: true }),
|
|
89
|
+
__metadata("design:type", String)
|
|
90
|
+
], TypeOrmBaseUser.prototype, "urlSlug", void 0);
|
|
91
|
+
__decorate([
|
|
92
|
+
(0, typeorm_1.Column)({ type: 'varchar', nullable: true, unique: true }),
|
|
93
|
+
__metadata("design:type", Object)
|
|
94
|
+
], TypeOrmBaseUser.prototype, "telegramId", void 0);
|
|
95
|
+
__decorate([
|
|
96
|
+
(0, type_graphql_1.Field)(() => String, { nullable: true }),
|
|
97
|
+
(0, typeorm_1.Column)({ type: 'varchar', nullable: true }),
|
|
98
|
+
__metadata("design:type", Object)
|
|
99
|
+
], TypeOrmBaseUser.prototype, "avatar", void 0);
|
|
100
|
+
__decorate([
|
|
101
|
+
(0, type_graphql_1.Field)(() => type_graphql_1.GraphQLTimestamp),
|
|
102
|
+
(0, typeorm_1.Column)({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' }),
|
|
103
|
+
__metadata("design:type", Date)
|
|
104
|
+
], TypeOrmBaseUser.prototype, "lastSeenAt", void 0);
|
|
105
|
+
__decorate([
|
|
106
|
+
(0, type_graphql_1.Field)(() => Boolean),
|
|
107
|
+
__metadata("design:type", Boolean),
|
|
108
|
+
__metadata("design:paramtypes", [])
|
|
109
|
+
], TypeOrmBaseUser.prototype, "isOnline", null);
|
|
110
|
+
__decorate([
|
|
111
|
+
(0, type_graphql_1.Field)(() => Boolean),
|
|
112
|
+
__metadata("design:type", Boolean),
|
|
113
|
+
__metadata("design:paramtypes", [])
|
|
114
|
+
], TypeOrmBaseUser.prototype, "isOnlineRecently", null);
|
|
115
|
+
exports.TypeOrmBaseUser = TypeOrmBaseUser = TypeOrmBaseUser_1 = __decorate([
|
|
116
|
+
(0, type_graphql_1.ObjectType)({ isAbstract: true })
|
|
117
|
+
], TypeOrmBaseUser);
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './types';
|
|
2
|
+
export * from './adapters/TypeOrmProfileAdapter';
|
|
3
|
+
export * from './entities/TypeOrmBaseUser';
|
|
4
|
+
export * from './services/ProfileAuthService';
|
|
5
|
+
export * from './services/ProfileEmailService';
|
|
6
|
+
export * from './dto';
|
|
7
|
+
export * from './resolvers/AuthResolver';
|
|
8
|
+
export * from './resolvers/ProfileResolver';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./adapters/TypeOrmProfileAdapter"), exports);
|
|
19
|
+
__exportStar(require("./entities/TypeOrmBaseUser"), exports);
|
|
20
|
+
__exportStar(require("./services/ProfileAuthService"), exports);
|
|
21
|
+
__exportStar(require("./services/ProfileEmailService"), exports);
|
|
22
|
+
__exportStar(require("./dto"), exports);
|
|
23
|
+
__exportStar(require("./resolvers/AuthResolver"), exports);
|
|
24
|
+
__exportStar(require("./resolvers/ProfileResolver"), exports);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ProfileAuthService } from '../services/ProfileAuthService';
|
|
2
|
+
import { ProfileContext } from '../types';
|
|
3
|
+
import { RegisterInput, LoginInput, ConfirmEmailInput, ForgotPasswordInput, RecoverPasswordInput } from '../dto';
|
|
4
|
+
export interface AuthResolverDependencies<TContext extends ProfileContext = ProfileContext> {
|
|
5
|
+
authService: ProfileAuthService;
|
|
6
|
+
userType: any;
|
|
7
|
+
onUserCreated?: (user: any, ctx: TContext) => Promise<void>;
|
|
8
|
+
onLogin?: (user: any, ctx: TContext) => Promise<void>;
|
|
9
|
+
onLogout?: (user: any, ctx: TContext) => Promise<void>;
|
|
10
|
+
onEmailConfirmed?: (user: any, ctx: TContext) => Promise<void>;
|
|
11
|
+
onPasswordRecovered?: (user: any, ctx: TContext) => Promise<void>;
|
|
12
|
+
logTelegramBot?: {
|
|
13
|
+
sendError: (msg: string) => Promise<any>;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export declare function createAuthResolver<TContext extends ProfileContext = ProfileContext>(deps: AuthResolverDependencies<TContext>): {
|
|
17
|
+
new (): {
|
|
18
|
+
register(input: RegisterInput, ctx: TContext): Promise<{
|
|
19
|
+
ok: boolean;
|
|
20
|
+
}>;
|
|
21
|
+
login(input: LoginInput, ctx: TContext): Promise<{
|
|
22
|
+
ok: boolean;
|
|
23
|
+
}>;
|
|
24
|
+
logout(ctx: TContext): Promise<{
|
|
25
|
+
ok: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
confirmEmail(input: ConfirmEmailInput, ctx: TContext): Promise<{
|
|
28
|
+
ok: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
forgotPassword(input: ForgotPasswordInput, ctx: TContext): Promise<{
|
|
31
|
+
confirmationLinkIsSent: boolean;
|
|
32
|
+
limitExpiresAt: number;
|
|
33
|
+
}>;
|
|
34
|
+
recoverPassword(input: RecoverPasswordInput, ctx: TContext): Promise<{
|
|
35
|
+
ok: boolean;
|
|
36
|
+
}>;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
15
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
16
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
17
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
18
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
19
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
20
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.createAuthResolver = createAuthResolver;
|
|
25
|
+
const type_graphql_1 = require("type-graphql");
|
|
26
|
+
const graphql_utils_1 = require("@os-team/graphql-utils");
|
|
27
|
+
const graphql_transformers_1 = require("@os-team/graphql-transformers");
|
|
28
|
+
const graphql_validators_1 = require("@os-team/graphql-validators");
|
|
29
|
+
const ProfileAuthService_1 = require("../services/ProfileAuthService");
|
|
30
|
+
const dto_1 = require("../dto");
|
|
31
|
+
function createAuthResolver(deps) {
|
|
32
|
+
const { authService, onUserCreated, onLogin, onLogout, onEmailConfirmed, onPasswordRecovered, logTelegramBot, userType } = deps;
|
|
33
|
+
let AuthResolver = class AuthResolver {
|
|
34
|
+
register(input, ctx) {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
const { t } = ctx;
|
|
37
|
+
if (yield authService.db.isEmailTaken(input.email)) {
|
|
38
|
+
throw new Error(t('validation:auth.emailExists'));
|
|
39
|
+
}
|
|
40
|
+
const passwordHash = yield authService.hashPassword(input.password);
|
|
41
|
+
const user = yield authService.db.createUser({
|
|
42
|
+
email: input.email,
|
|
43
|
+
passwordHash,
|
|
44
|
+
});
|
|
45
|
+
if (onUserCreated)
|
|
46
|
+
yield onUserCreated(user, ctx);
|
|
47
|
+
if (logTelegramBot)
|
|
48
|
+
yield logTelegramBot.sendError(`Новый пользователь ${input.email}`);
|
|
49
|
+
// Создаем сессию
|
|
50
|
+
const userAgent = decodeURI(ctx.req.get('user-agent') || '');
|
|
51
|
+
yield ctx.req.session.create({
|
|
52
|
+
userId: user.id,
|
|
53
|
+
ip: ctx.req.ip,
|
|
54
|
+
userAgent: userAgent.slice(0, 500),
|
|
55
|
+
});
|
|
56
|
+
return { ok: true };
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
login(input, ctx) {
|
|
60
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
+
const { t } = ctx;
|
|
62
|
+
const user = yield authService.db.findUserByEmail(input.email);
|
|
63
|
+
if (!user)
|
|
64
|
+
throw new Error(t('validation:user.notFound'));
|
|
65
|
+
if (user.isBanned)
|
|
66
|
+
throw new Error(t('validation:user.banned'));
|
|
67
|
+
const isPasswordOk = yield authService.verifyPassword(user.password, input.password);
|
|
68
|
+
if (!isPasswordOk)
|
|
69
|
+
throw new Error(t('validation:login.wrongPassword'));
|
|
70
|
+
const userAgent = decodeURI(ctx.req.get('user-agent') || '');
|
|
71
|
+
yield ctx.req.session.create({
|
|
72
|
+
userId: user.id,
|
|
73
|
+
ip: ctx.req.ip,
|
|
74
|
+
userAgent: userAgent.slice(0, 500),
|
|
75
|
+
});
|
|
76
|
+
if (onLogin)
|
|
77
|
+
yield onLogin(user, ctx);
|
|
78
|
+
if (logTelegramBot) {
|
|
79
|
+
yield logTelegramBot.sendError(`${user.email || user.urlSlug} вошел(ла) на сайт`);
|
|
80
|
+
}
|
|
81
|
+
return { ok: true };
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
logout(ctx) {
|
|
85
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
86
|
+
const { user } = ctx;
|
|
87
|
+
if (onLogout)
|
|
88
|
+
yield onLogout(user, ctx);
|
|
89
|
+
if (logTelegramBot) {
|
|
90
|
+
yield logTelegramBot.sendError(`${user && (user.email || user.urlSlug)} разлогинился(лась)`);
|
|
91
|
+
}
|
|
92
|
+
yield ctx.req.session.destroy();
|
|
93
|
+
return { ok: true };
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
confirmEmail(input, ctx) {
|
|
97
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
98
|
+
const user = yield authService.getUserByToken(ProfileAuthService_1.CONFIRMATION_REDIS_PREFIX, input.token);
|
|
99
|
+
if (!user)
|
|
100
|
+
throw new Error(ctx.t('validation:error.wrongCode'));
|
|
101
|
+
user.isEmailConfirmed = true;
|
|
102
|
+
yield user.save();
|
|
103
|
+
yield authService.removeTokenFromRedis(ProfileAuthService_1.CONFIRMATION_REDIS_PREFIX, user, input.token);
|
|
104
|
+
const userAgent = decodeURI(ctx.req.get('user-agent') || '');
|
|
105
|
+
yield ctx.req.session.create({
|
|
106
|
+
userId: user.id,
|
|
107
|
+
ip: ctx.req.ip,
|
|
108
|
+
userAgent: userAgent.slice(0, 500),
|
|
109
|
+
});
|
|
110
|
+
if (onEmailConfirmed)
|
|
111
|
+
yield onEmailConfirmed(user, ctx);
|
|
112
|
+
if (logTelegramBot) {
|
|
113
|
+
yield logTelegramBot.sendError(`${user.email || user.urlSlug} подтвердил(а) email`);
|
|
114
|
+
}
|
|
115
|
+
return { ok: true };
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
forgotPassword(input, ctx) {
|
|
119
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
120
|
+
const { t } = ctx;
|
|
121
|
+
const user = yield authService.db.findUserByEmail(input.email);
|
|
122
|
+
if (!user)
|
|
123
|
+
throw new Error(t('validation:forgot.errors.notRegistered'));
|
|
124
|
+
const res = yield authService.sendLink(user, 'recovery');
|
|
125
|
+
if (logTelegramBot) {
|
|
126
|
+
yield logTelegramBot.sendError(`${user.email || user.urlSlug} запросил(а) восстановление пароля`);
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
confirmationLinkIsSent: res.ok,
|
|
130
|
+
limitExpiresAt: res.limitExpiresAt,
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
recoverPassword(input, ctx) {
|
|
135
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
136
|
+
const user = yield authService.getUserByToken(ProfileAuthService_1.RECOVERY_REDIS_PREFIX, input.token);
|
|
137
|
+
if (!user)
|
|
138
|
+
throw new Error(ctx.t('validation:error.wrongCode'));
|
|
139
|
+
user.password = yield authService.hashPassword(input.password);
|
|
140
|
+
user.isTempPassword = false;
|
|
141
|
+
yield user.save();
|
|
142
|
+
yield authService.removeTokenFromRedis(ProfileAuthService_1.RECOVERY_REDIS_PREFIX, user, input.token);
|
|
143
|
+
const userAgent = decodeURI(ctx.req.get('user-agent') || '');
|
|
144
|
+
yield ctx.req.session.create({
|
|
145
|
+
userId: user.id,
|
|
146
|
+
ip: ctx.req.ip,
|
|
147
|
+
userAgent: userAgent.slice(0, 500),
|
|
148
|
+
});
|
|
149
|
+
if (onPasswordRecovered)
|
|
150
|
+
yield onPasswordRecovered(user, ctx);
|
|
151
|
+
if (logTelegramBot) {
|
|
152
|
+
yield logTelegramBot.sendError(`${user.email || user.urlSlug} восстановил(а) пароль`);
|
|
153
|
+
}
|
|
154
|
+
return { ok: true };
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
__decorate([
|
|
159
|
+
(0, graphql_transformers_1.TransformArgs)(dto_1.registerTransformers, { arg: 'input' }),
|
|
160
|
+
(0, graphql_validators_1.ValidateArgs)(dto_1.registerValidators, { arg: 'input', tKey: 'register' }),
|
|
161
|
+
(0, type_graphql_1.Mutation)(() => graphql_utils_1.StatusPayload),
|
|
162
|
+
__param(0, (0, type_graphql_1.Arg)('input')),
|
|
163
|
+
__param(1, (0, type_graphql_1.Ctx)()),
|
|
164
|
+
__metadata("design:type", Function),
|
|
165
|
+
__metadata("design:paramtypes", [dto_1.RegisterInput, Object]),
|
|
166
|
+
__metadata("design:returntype", Promise)
|
|
167
|
+
], AuthResolver.prototype, "register", null);
|
|
168
|
+
__decorate([
|
|
169
|
+
(0, graphql_transformers_1.TransformArgs)(dto_1.loginTransformers, { arg: 'input' }),
|
|
170
|
+
(0, graphql_validators_1.ValidateArgs)(dto_1.loginValidators, { arg: 'input', tKey: 'register' }),
|
|
171
|
+
(0, type_graphql_1.Mutation)(() => graphql_utils_1.StatusPayload),
|
|
172
|
+
__param(0, (0, type_graphql_1.Arg)('input')),
|
|
173
|
+
__param(1, (0, type_graphql_1.Ctx)()),
|
|
174
|
+
__metadata("design:type", Function),
|
|
175
|
+
__metadata("design:paramtypes", [dto_1.LoginInput, Object]),
|
|
176
|
+
__metadata("design:returntype", Promise)
|
|
177
|
+
], AuthResolver.prototype, "login", null);
|
|
178
|
+
__decorate([
|
|
179
|
+
(0, type_graphql_1.Authorized)(),
|
|
180
|
+
(0, type_graphql_1.Mutation)(() => graphql_utils_1.StatusPayload),
|
|
181
|
+
__param(0, (0, type_graphql_1.Ctx)()),
|
|
182
|
+
__metadata("design:type", Function),
|
|
183
|
+
__metadata("design:paramtypes", [Object]),
|
|
184
|
+
__metadata("design:returntype", Promise)
|
|
185
|
+
], AuthResolver.prototype, "logout", null);
|
|
186
|
+
__decorate([
|
|
187
|
+
(0, graphql_validators_1.ValidateArgs)(dto_1.confirmEmailValidators, { arg: 'input', tKey: 'confirmEmail' }),
|
|
188
|
+
(0, type_graphql_1.Mutation)(() => graphql_utils_1.StatusPayload),
|
|
189
|
+
__param(0, (0, type_graphql_1.Arg)('input')),
|
|
190
|
+
__param(1, (0, type_graphql_1.Ctx)()),
|
|
191
|
+
__metadata("design:type", Function),
|
|
192
|
+
__metadata("design:paramtypes", [dto_1.ConfirmEmailInput, Object]),
|
|
193
|
+
__metadata("design:returntype", Promise)
|
|
194
|
+
], AuthResolver.prototype, "confirmEmail", null);
|
|
195
|
+
__decorate([
|
|
196
|
+
(0, graphql_transformers_1.TransformArgs)(dto_1.forgotPasswordTransformers, { arg: 'input' }),
|
|
197
|
+
(0, graphql_validators_1.ValidateArgs)(dto_1.forgotPasswordValidators, { arg: 'input', tKey: 'forgot' }),
|
|
198
|
+
(0, type_graphql_1.Mutation)(() => dto_1.SendTokenPayload),
|
|
199
|
+
__param(0, (0, type_graphql_1.Arg)('input')),
|
|
200
|
+
__param(1, (0, type_graphql_1.Ctx)()),
|
|
201
|
+
__metadata("design:type", Function),
|
|
202
|
+
__metadata("design:paramtypes", [dto_1.ForgotPasswordInput, Object]),
|
|
203
|
+
__metadata("design:returntype", Promise)
|
|
204
|
+
], AuthResolver.prototype, "forgotPassword", null);
|
|
205
|
+
__decorate([
|
|
206
|
+
(0, graphql_transformers_1.TransformArgs)(dto_1.recoverPasswordTransformers, { arg: 'input' }),
|
|
207
|
+
(0, graphql_validators_1.ValidateArgs)(dto_1.recoverPasswordValidators, { arg: 'input', tKey: 'recover' }),
|
|
208
|
+
(0, type_graphql_1.Mutation)(() => graphql_utils_1.StatusPayload),
|
|
209
|
+
__param(0, (0, type_graphql_1.Arg)('input')),
|
|
210
|
+
__param(1, (0, type_graphql_1.Ctx)()),
|
|
211
|
+
__metadata("design:type", Function),
|
|
212
|
+
__metadata("design:paramtypes", [dto_1.RecoverPasswordInput, Object]),
|
|
213
|
+
__metadata("design:returntype", Promise)
|
|
214
|
+
], AuthResolver.prototype, "recoverPassword", null);
|
|
215
|
+
AuthResolver = __decorate([
|
|
216
|
+
(0, type_graphql_1.Resolver)(() => userType)
|
|
217
|
+
], AuthResolver);
|
|
218
|
+
return AuthResolver;
|
|
219
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ProfileAuthService } from '../services/ProfileAuthService';
|
|
2
|
+
import { ProfileContext } from '../types';
|
|
3
|
+
import { UpdateEmailInput, UpdatePasswordInput, UpdateProfileInput } from '../dto';
|
|
4
|
+
export interface ProfileResolverDependencies {
|
|
5
|
+
authService: ProfileAuthService;
|
|
6
|
+
userType: any;
|
|
7
|
+
}
|
|
8
|
+
export declare function createProfileResolver<TContext extends ProfileContext = ProfileContext>(deps: ProfileResolverDependencies): {
|
|
9
|
+
new (): {
|
|
10
|
+
updateEmail(input: UpdateEmailInput, ctx: TContext): Promise<{
|
|
11
|
+
ok: boolean;
|
|
12
|
+
}>;
|
|
13
|
+
updatePassword(input: UpdatePasswordInput, ctx: TContext): Promise<{
|
|
14
|
+
ok: boolean;
|
|
15
|
+
}>;
|
|
16
|
+
updateProfile(input: UpdateProfileInput, ctx: TContext): Promise<import("../types").AuthUser>;
|
|
17
|
+
toggleEmailNotification(ctx: TContext): Promise<{
|
|
18
|
+
ok: boolean;
|
|
19
|
+
}>;
|
|
20
|
+
toggleTelegramNotification(ctx: TContext): Promise<{
|
|
21
|
+
ok: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
15
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
16
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
17
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
18
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
19
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
20
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.createProfileResolver = createProfileResolver;
|
|
25
|
+
const type_graphql_1 = require("type-graphql");
|
|
26
|
+
const graphql_utils_1 = require("@os-team/graphql-utils");
|
|
27
|
+
const graphql_transformers_1 = require("@os-team/graphql-transformers");
|
|
28
|
+
const graphql_validators_1 = require("@os-team/graphql-validators");
|
|
29
|
+
const dto_1 = require("../dto");
|
|
30
|
+
function createProfileResolver(deps) {
|
|
31
|
+
const { authService, userType } = deps;
|
|
32
|
+
let ProfileResolver = class ProfileResolver {
|
|
33
|
+
updateEmail(input, ctx) {
|
|
34
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
+
const { user, t } = ctx;
|
|
36
|
+
if (!user)
|
|
37
|
+
throw new type_graphql_1.UnauthorizedError();
|
|
38
|
+
if (yield authService.db.isEmailTaken(input.email, user.id)) {
|
|
39
|
+
throw new Error(t('validation:updateEmail.emailExists'));
|
|
40
|
+
}
|
|
41
|
+
user.email = input.email;
|
|
42
|
+
user.isEmailConfirmed = false;
|
|
43
|
+
yield user.save();
|
|
44
|
+
return { ok: true };
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
updatePassword(input, ctx) {
|
|
48
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
const { user, t } = ctx;
|
|
50
|
+
if (!user)
|
|
51
|
+
throw new type_graphql_1.UnauthorizedError();
|
|
52
|
+
const isOldPasswordOk = yield authService.verifyPassword(user.password, input.oldPassword);
|
|
53
|
+
if (!isOldPasswordOk)
|
|
54
|
+
throw new Error(t('validation:updatePassword.wrongPassword'));
|
|
55
|
+
user.password = yield authService.hashPassword(input.password);
|
|
56
|
+
user.isTempPassword = false;
|
|
57
|
+
yield user.save();
|
|
58
|
+
return { ok: true };
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
updateProfile(input, ctx) {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
const { user } = ctx;
|
|
64
|
+
if (!user)
|
|
65
|
+
throw new type_graphql_1.UnauthorizedError();
|
|
66
|
+
user.name = input.name;
|
|
67
|
+
yield user.save();
|
|
68
|
+
return user;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
toggleEmailNotification(ctx) {
|
|
72
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
const { user } = ctx;
|
|
74
|
+
if (!user)
|
|
75
|
+
throw new type_graphql_1.UnauthorizedError();
|
|
76
|
+
user.isEmailNotificationEnabled = !user.isEmailNotificationEnabled;
|
|
77
|
+
yield user.save();
|
|
78
|
+
return { ok: true };
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
toggleTelegramNotification(ctx) {
|
|
82
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
83
|
+
const { user } = ctx;
|
|
84
|
+
if (!user)
|
|
85
|
+
throw new type_graphql_1.UnauthorizedError();
|
|
86
|
+
user.isTelegramNotificationEnabled = !user.isTelegramNotificationEnabled;
|
|
87
|
+
yield user.save();
|
|
88
|
+
return { ok: true };
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
__decorate([
|
|
93
|
+
(0, type_graphql_1.Authorized)(),
|
|
94
|
+
(0, graphql_transformers_1.TransformArgs)(dto_1.updateEmailTransformers, { arg: 'input' }),
|
|
95
|
+
(0, graphql_validators_1.ValidateArgs)(dto_1.updateEmailValidators, { arg: 'input', tKey: 'updateEmail' }),
|
|
96
|
+
(0, type_graphql_1.Mutation)(() => graphql_utils_1.StatusPayload),
|
|
97
|
+
__param(0, (0, type_graphql_1.Arg)('input')),
|
|
98
|
+
__param(1, (0, type_graphql_1.Ctx)()),
|
|
99
|
+
__metadata("design:type", Function),
|
|
100
|
+
__metadata("design:paramtypes", [dto_1.UpdateEmailInput, Object]),
|
|
101
|
+
__metadata("design:returntype", Promise)
|
|
102
|
+
], ProfileResolver.prototype, "updateEmail", null);
|
|
103
|
+
__decorate([
|
|
104
|
+
(0, type_graphql_1.Authorized)(),
|
|
105
|
+
(0, graphql_transformers_1.TransformArgs)(dto_1.updatePasswordTransformers, { arg: 'input' }),
|
|
106
|
+
(0, graphql_validators_1.ValidateArgs)(dto_1.updatePasswordValidators, { arg: 'input', tKey: 'updatePassword' }),
|
|
107
|
+
(0, type_graphql_1.Mutation)(() => graphql_utils_1.StatusPayload),
|
|
108
|
+
__param(0, (0, type_graphql_1.Arg)('input')),
|
|
109
|
+
__param(1, (0, type_graphql_1.Ctx)()),
|
|
110
|
+
__metadata("design:type", Function),
|
|
111
|
+
__metadata("design:paramtypes", [dto_1.UpdatePasswordInput, Object]),
|
|
112
|
+
__metadata("design:returntype", Promise)
|
|
113
|
+
], ProfileResolver.prototype, "updatePassword", null);
|
|
114
|
+
__decorate([
|
|
115
|
+
(0, type_graphql_1.Authorized)(),
|
|
116
|
+
(0, graphql_transformers_1.TransformArgs)(dto_1.updateProfileTransformers, { arg: 'input' }),
|
|
117
|
+
(0, graphql_validators_1.ValidateArgs)(dto_1.updateProfileValidators, { arg: 'input', tKey: 'updateProfile' }),
|
|
118
|
+
(0, type_graphql_1.Mutation)(() => userType),
|
|
119
|
+
__param(0, (0, type_graphql_1.Arg)('input')),
|
|
120
|
+
__param(1, (0, type_graphql_1.Ctx)()),
|
|
121
|
+
__metadata("design:type", Function),
|
|
122
|
+
__metadata("design:paramtypes", [dto_1.UpdateProfileInput, Object]),
|
|
123
|
+
__metadata("design:returntype", Promise)
|
|
124
|
+
], ProfileResolver.prototype, "updateProfile", null);
|
|
125
|
+
__decorate([
|
|
126
|
+
(0, type_graphql_1.Authorized)(),
|
|
127
|
+
(0, type_graphql_1.Mutation)(() => graphql_utils_1.StatusPayload),
|
|
128
|
+
__param(0, (0, type_graphql_1.Ctx)()),
|
|
129
|
+
__metadata("design:type", Function),
|
|
130
|
+
__metadata("design:paramtypes", [Object]),
|
|
131
|
+
__metadata("design:returntype", Promise)
|
|
132
|
+
], ProfileResolver.prototype, "toggleEmailNotification", null);
|
|
133
|
+
__decorate([
|
|
134
|
+
(0, type_graphql_1.Authorized)(),
|
|
135
|
+
(0, type_graphql_1.Mutation)(() => graphql_utils_1.StatusPayload),
|
|
136
|
+
__param(0, (0, type_graphql_1.Ctx)()),
|
|
137
|
+
__metadata("design:type", Function),
|
|
138
|
+
__metadata("design:paramtypes", [Object]),
|
|
139
|
+
__metadata("design:returntype", Promise)
|
|
140
|
+
], ProfileResolver.prototype, "toggleTelegramNotification", null);
|
|
141
|
+
ProfileResolver = __decorate([
|
|
142
|
+
(0, type_graphql_1.Resolver)(() => userType)
|
|
143
|
+
], ProfileResolver);
|
|
144
|
+
return ProfileResolver;
|
|
145
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Redis } from 'ioredis';
|
|
2
|
+
import { AuthUser, ProfileAuthConfig, ProfileDbAdapter } from '../types';
|
|
3
|
+
import { ProfileEmailService } from './ProfileEmailService';
|
|
4
|
+
export declare const CONFIRMATION_REDIS_PREFIX = "conf";
|
|
5
|
+
export declare const RECOVERY_REDIS_PREFIX = "rec";
|
|
6
|
+
export declare const TOKEN_REDIS_POSTFIX = "token";
|
|
7
|
+
export declare const LAST_SENT_AT_REDIS_POSTFIX = "lastSentAt";
|
|
8
|
+
export declare class ProfileAuthService {
|
|
9
|
+
db: ProfileDbAdapter;
|
|
10
|
+
email: ProfileEmailService;
|
|
11
|
+
redis: Redis;
|
|
12
|
+
config: ProfileAuthConfig;
|
|
13
|
+
constructor(db: ProfileDbAdapter, email: ProfileEmailService, redis: Redis, config: ProfileAuthConfig);
|
|
14
|
+
hashPassword(password: string): Promise<string>;
|
|
15
|
+
verifyPassword(hash: string, password: string): Promise<boolean>;
|
|
16
|
+
private getLimitMs;
|
|
17
|
+
setTokenToRedis(prefix: string, user: AuthUser, token: string, ttlMinutes: number): Promise<void>;
|
|
18
|
+
sendLink(user: AuthUser, type: 'confirmation' | 'recovery'): Promise<{
|
|
19
|
+
ok: boolean;
|
|
20
|
+
limitExpiresAt: number;
|
|
21
|
+
}>;
|
|
22
|
+
getUserByToken(prefix: string, token: string): Promise<AuthUser | null>;
|
|
23
|
+
removeTokenFromRedis(prefix: string, user: AuthUser, token: string): Promise<void>;
|
|
24
|
+
}
|