@skroz/profile-api 1.0.17 → 1.0.19

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.
@@ -7,6 +7,7 @@ interface AppleOauthConfig {
7
7
  }
8
8
  export declare class AppleOauth implements OAuthProvider {
9
9
  private config;
10
+ readonly trustedEmail = true;
10
11
  constructor(config: AppleOauthConfig);
11
12
  exchangeCode(code: string): Promise<OAuthProfile>;
12
13
  }
@@ -47,6 +47,9 @@ function decodeJwtPayload(token) {
47
47
  class AppleOauth {
48
48
  constructor(config) {
49
49
  this.config = config;
50
+ // Apple provides email only on first authorization. On subsequent logins email will be null,
51
+ // so confirmation flags are only set when email is actually present in the profile.
52
+ this.trustedEmail = true;
50
53
  }
51
54
  exchangeCode(code) {
52
55
  return __awaiter(this, void 0, void 0, function* () {
@@ -6,6 +6,7 @@ interface GoogleOauthConfig {
6
6
  }
7
7
  export declare class GoogleOauth implements OAuthProvider {
8
8
  private config;
9
+ readonly trustedEmail = true;
9
10
  constructor(config: GoogleOauthConfig);
10
11
  exchangeCode(code: string): Promise<OAuthProfile>;
11
12
  }
@@ -17,6 +17,7 @@ const isomorphic_unfetch_1 = __importDefault(require("isomorphic-unfetch"));
17
17
  class GoogleOauth {
18
18
  constructor(config) {
19
19
  this.config = config;
20
+ this.trustedEmail = true;
20
21
  }
21
22
  exchangeCode(code) {
22
23
  return __awaiter(this, void 0, void 0, function* () {
@@ -6,6 +6,7 @@ interface MailOauthConfig {
6
6
  }
7
7
  export declare class MailOauth implements OAuthProvider {
8
8
  private config;
9
+ readonly trustedEmail = true;
9
10
  constructor(config: MailOauthConfig);
10
11
  exchangeCode(code: string): Promise<OAuthProfile>;
11
12
  }
@@ -18,6 +18,7 @@ const crypto_1 = __importDefault(require("crypto"));
18
18
  class MailOauth {
19
19
  constructor(config) {
20
20
  this.config = config;
21
+ this.trustedEmail = true;
21
22
  }
22
23
  exchangeCode(code) {
23
24
  return __awaiter(this, void 0, void 0, function* () {
@@ -6,4 +6,12 @@ export interface OAuthProfile {
6
6
  }
7
7
  export interface OAuthProvider {
8
8
  exchangeCode(code: string): Promise<OAuthProfile>;
9
+ /**
10
+ * Whether this provider verifies the user's email address.
11
+ * When true, isEmailConfirmed and isEmailNotificationEnabled are automatically
12
+ * set to true upon login/registration via this provider.
13
+ *
14
+ * Set to false for providers that do not supply a verified email (e.g. Telegram).
15
+ */
16
+ readonly trustedEmail: boolean;
9
17
  }
@@ -6,6 +6,7 @@ interface VKOauthConfig {
6
6
  }
7
7
  export declare class VKOauth implements OAuthProvider {
8
8
  private config;
9
+ readonly trustedEmail = true;
9
10
  constructor(config: VKOauthConfig);
10
11
  exchangeCode(code: string): Promise<OAuthProfile>;
11
12
  }
@@ -17,6 +17,9 @@ const isomorphic_unfetch_1 = __importDefault(require("isomorphic-unfetch"));
17
17
  class VKOauth {
18
18
  constructor(config) {
19
19
  this.config = config;
20
+ // VK returns email only if the user has a confirmed email in their account and grants access.
21
+ // If email is absent, trustedEmail guard in the resolver prevents setting confirmation flags.
22
+ this.trustedEmail = true;
20
23
  }
21
24
  exchangeCode(code) {
22
25
  return __awaiter(this, void 0, void 0, function* () {
@@ -5,6 +5,7 @@ interface YandexOauthConfig {
5
5
  }
6
6
  export declare class YandexOauth implements OAuthProvider {
7
7
  private config;
8
+ readonly trustedEmail = true;
8
9
  constructor(config: YandexOauthConfig);
9
10
  exchangeCode(code: string): Promise<OAuthProfile>;
10
11
  }
@@ -17,6 +17,7 @@ const isomorphic_unfetch_1 = __importDefault(require("isomorphic-unfetch"));
17
17
  class YandexOauth {
18
18
  constructor(config) {
19
19
  this.config = config;
20
+ this.trustedEmail = true;
20
21
  }
21
22
  exchangeCode(code) {
22
23
  return __awaiter(this, void 0, void 0, function* () {
@@ -56,9 +56,11 @@ function createProfileResolver(deps) {
56
56
  if (!user)
57
57
  throw new type_graphql_1.UnauthorizedError();
58
58
  const service = getAuthService(ctx);
59
- const isOldPasswordOk = yield service.verifyPassword(user.password, input.oldPassword);
60
- if (!isOldPasswordOk)
61
- throw new Error(t('validation:updatePassword.wrongPassword'));
59
+ if (!user.isTempPassword) {
60
+ const isOldPasswordOk = yield service.verifyPassword(user.password, input.oldPassword);
61
+ if (!isOldPasswordOk)
62
+ throw new Error(t('validation:updatePassword.wrongPassword'));
63
+ }
62
64
  user.password = yield service.hashPassword(input.password);
63
65
  user.isTempPassword = false;
64
66
  yield user.save();
@@ -114,6 +114,12 @@ function createOauthResolver(deps) {
114
114
  yield service.db.updateUserProviderId(user.id, input.provider, profile.providerId);
115
115
  isNew = true;
116
116
  }
117
+ // Auto-confirm email for trusted providers when email is present
118
+ if (provider.trustedEmail && profile.email && (!user.isEmailConfirmed || !user.isEmailNotificationEnabled)) {
119
+ user.isEmailConfirmed = true;
120
+ user.isEmailNotificationEnabled = true;
121
+ yield user.save();
122
+ }
117
123
  }
118
124
  if (user.isBanned)
119
125
  throw new Error('User is banned');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skroz/profile-api",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "license": "MIT",
5
5
  "repository": "git@gitlab.com:skroz/libs/utils.git",
6
6
  "main": "dist/index.js",
@@ -44,5 +44,5 @@
44
44
  "type-graphql": "^1.1.1",
45
45
  "typeorm": "^0.2.45"
46
46
  },
47
- "gitHead": "f3b755fdd93c8da958f3d94da50d2393fafdfdc5"
47
+ "gitHead": "ad9d511d8f623ad1a5d3a6a83e016c4b12d4f211"
48
48
  }
@@ -43,6 +43,10 @@ function decodeJwtPayload(token: string): Record<string, any> {
43
43
  }
44
44
 
45
45
  export class AppleOauth implements OAuthProvider {
46
+ // Apple provides email only on first authorization. On subsequent logins email will be null,
47
+ // so confirmation flags are only set when email is actually present in the profile.
48
+ readonly trustedEmail = true;
49
+
46
50
  constructor(private config: AppleOauthConfig) {}
47
51
 
48
52
  async exchangeCode(code: string): Promise<OAuthProfile> {
@@ -8,6 +8,8 @@ interface GoogleOauthConfig {
8
8
  }
9
9
 
10
10
  export class GoogleOauth implements OAuthProvider {
11
+ readonly trustedEmail = true;
12
+
11
13
  constructor(private config: GoogleOauthConfig) {}
12
14
 
13
15
  async exchangeCode(code: string): Promise<OAuthProfile> {
@@ -9,6 +9,8 @@ interface MailOauthConfig {
9
9
  }
10
10
 
11
11
  export class MailOauth implements OAuthProvider {
12
+ readonly trustedEmail = true;
13
+
12
14
  constructor(private config: MailOauthConfig) {}
13
15
 
14
16
  async exchangeCode(code: string): Promise<OAuthProfile> {
@@ -7,4 +7,12 @@ export interface OAuthProfile {
7
7
 
8
8
  export interface OAuthProvider {
9
9
  exchangeCode(code: string): Promise<OAuthProfile>;
10
+ /**
11
+ * Whether this provider verifies the user's email address.
12
+ * When true, isEmailConfirmed and isEmailNotificationEnabled are automatically
13
+ * set to true upon login/registration via this provider.
14
+ *
15
+ * Set to false for providers that do not supply a verified email (e.g. Telegram).
16
+ */
17
+ readonly trustedEmail: boolean;
10
18
  }
@@ -8,6 +8,10 @@ interface VKOauthConfig {
8
8
  }
9
9
 
10
10
  export class VKOauth implements OAuthProvider {
11
+ // VK returns email only if the user has a confirmed email in their account and grants access.
12
+ // If email is absent, trustedEmail guard in the resolver prevents setting confirmation flags.
13
+ readonly trustedEmail = true;
14
+
11
15
  constructor(private config: VKOauthConfig) {}
12
16
 
13
17
  async exchangeCode(code: string): Promise<OAuthProfile> {
@@ -7,6 +7,8 @@ interface YandexOauthConfig {
7
7
  }
8
8
 
9
9
  export class YandexOauth implements OAuthProvider {
10
+ readonly trustedEmail = true;
11
+
10
12
  constructor(private config: YandexOauthConfig) {}
11
13
 
12
14
  async exchangeCode(code: string): Promise<OAuthProfile> {
@@ -80,12 +80,14 @@ export function createProfileResolver<
80
80
  if (!user) throw new UnauthorizedError();
81
81
 
82
82
  const service = getAuthService(ctx);
83
- const isOldPasswordOk = await service.verifyPassword(
84
- user.password!,
85
- input.oldPassword
86
- );
87
- if (!isOldPasswordOk)
88
- throw new Error(t('validation:updatePassword.wrongPassword'));
83
+ if (!user.isTempPassword) {
84
+ const isOldPasswordOk = await service.verifyPassword(
85
+ user.password!,
86
+ input.oldPassword
87
+ );
88
+ if (!isOldPasswordOk)
89
+ throw new Error(t('validation:updatePassword.wrongPassword'));
90
+ }
89
91
 
90
92
  user.password = await service.hashPassword(input.password);
91
93
  user.isTempPassword = false;
@@ -114,6 +114,13 @@ export function createOauthResolver<
114
114
  await service.db.updateUserProviderId(user.id, input.provider, profile.providerId);
115
115
  isNew = true;
116
116
  }
117
+
118
+ // Auto-confirm email for trusted providers when email is present
119
+ if (provider.trustedEmail && profile.email && (!user.isEmailConfirmed || !user.isEmailNotificationEnabled)) {
120
+ user.isEmailConfirmed = true;
121
+ user.isEmailNotificationEnabled = true;
122
+ await user.save();
123
+ }
117
124
  }
118
125
 
119
126
  if (user.isBanned) throw new Error('User is banned');