fiber-firebase-functions 1.0.3 → 1.0.4
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/README.md +74 -0
- package/lib/auth/is_user_disabled.js +37 -36
- package/lib/auth/is_user_disabled.js.map +1 -1
- package/lib/auth/is_user_exists.js +31 -30
- package/lib/auth/is_user_exists.js.map +1 -1
- package/lib/auth/otp.js +92 -25
- package/lib/auth/otp.js.map +1 -1
- package/lib/auth/reset_password.js +327 -0
- package/lib/auth/reset_password.js.map +1 -0
- package/lib/auth/user.js +44 -32
- package/lib/auth/user.js.map +1 -1
- package/lib/common/config.js +9 -5
- package/lib/common/config.js.map +1 -1
- package/lib/common/locale.js +119 -0
- package/lib/common/locale.js.map +1 -0
- package/lib/email/email.js +96 -0
- package/lib/email/email.js.map +1 -0
- package/lib/email/templates/new_user.js +491 -0
- package/lib/email/templates/new_user.js.map +1 -0
- package/{src/email/send_email.ts → lib/email/templates.js} +7 -17
- package/lib/email/templates.js.map +1 -0
- package/lib/index.js +6 -0
- package/lib/index.js.map +1 -1
- package/lib/middleware/rate_limiter.js +8 -8
- package/lib/middleware/rate_limiter.js.map +1 -1
- package/package.json +6 -4
- package/src/auth/is_user_disabled.ts +31 -29
- package/src/auth/is_user_exists.ts +25 -23
- package/src/auth/otp.ts +89 -24
- package/src/auth/reset_password.ts +317 -0
- package/src/auth/user.ts +34 -24
- package/src/common/config.ts +20 -10
- package/src/common/locale.ts +121 -0
- package/src/email/email.ts +70 -0
- package/src/email/templates/new_user.ts +493 -0
- package/src/email/templates.ts +34 -0
- package/src/index.ts +6 -0
- package/src/middleware/rate_limiter.ts +8 -8
- package/src/auth/update_password.ts +0 -224
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://fiberstudio.app/assets/images/fiber.png" alt="Fiber Logo" width="160" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
# fiber-firebase-functions
|
|
9
|
+
|
|
10
|
+
A collection of ready-to-use Firebase Cloud Functions utilities and wrappers designed for any application built by Fiber. Provides reusable helpers, common patterns, and production-grade modules to streamline backend development across all Fiber projects.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
Install the package using one of the following commands:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm i fiber-firebase-functions
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Configuration
|
|
21
|
+
|
|
22
|
+
After installing the package, the first required step is to create an `app.json` file at the root of your Cloud Functions project.
|
|
23
|
+
This file contains all configuration values needed by the package and is automatically loaded at runtime.
|
|
24
|
+
|
|
25
|
+
Your project structure should look like:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
functions/
|
|
29
|
+
├─ src/
|
|
30
|
+
├─ package.json
|
|
31
|
+
├─ app.json ← required configuration file
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
You can then define your configuration keys inside `app.json`.
|
|
35
|
+
Examples are provided below.
|
|
36
|
+
|
|
37
|
+
If you plan to use the functions:
|
|
38
|
+
|
|
39
|
+
- isRateLimited
|
|
40
|
+
- recordRateLimitHit
|
|
41
|
+
- ResetPassword.withEmail
|
|
42
|
+
- ResetPassword.withId
|
|
43
|
+
|
|
44
|
+
You must provide a middleware configuration inside your `app.json`.
|
|
45
|
+
This middleware is used internally by the package to apply rate-limiting logic and return the appropriate response when a user performs too many requests.
|
|
46
|
+
|
|
47
|
+
Here is the minimal required configuration:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"rate_limiter": {
|
|
52
|
+
"app_name": "rateLimiter",
|
|
53
|
+
"url": "https://database.com"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Make sure the `url` points to your Realtime Database instance and that the `app_name` matches your internal configuration.
|
|
59
|
+
|
|
60
|
+
If you want to enable email sending through this package, you must first install and configure the **Trigger Email From Firestore** extension.
|
|
61
|
+
Once the extension is set up, you need to define an `email` section in your `app.json`.
|
|
62
|
+
|
|
63
|
+
Here is the required configuration:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"email": {
|
|
68
|
+
"application_name": "MyFiber",
|
|
69
|
+
"collection": "__fbs__email"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The `application_name` corresponds to the name of your application, and the `collection` must match the Firestore collection monitored by the extension.
|
|
@@ -63,9 +63,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
63
63
|
};
|
|
64
64
|
})();
|
|
65
65
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
66
|
-
exports.UserDisabledByEmailStatus = exports.UserDisabledByIdStatus = void 0;
|
|
67
|
-
exports.isUserDisabledById = isUserDisabledById;
|
|
68
|
-
exports.isUserDisabledByEmail = isUserDisabledByEmail;
|
|
66
|
+
exports.IsUserDisabled = exports.UserDisabledByEmailStatus = exports.UserDisabledByIdStatus = void 0;
|
|
69
67
|
const admin = __importStar(require("firebase-admin"));
|
|
70
68
|
if (admin.apps.length === 0) {
|
|
71
69
|
admin.initializeApp();
|
|
@@ -75,7 +73,7 @@ var UserDisabledByIdStatus;
|
|
|
75
73
|
UserDisabledByIdStatus["MISSING_USER_ID"] = "MISSING_USER_ID";
|
|
76
74
|
UserDisabledByIdStatus["ENABLED"] = "ENABLED";
|
|
77
75
|
UserDisabledByIdStatus["DISABLED"] = "DISABLED";
|
|
78
|
-
UserDisabledByIdStatus["
|
|
76
|
+
UserDisabledByIdStatus["USER_NOT_FOUND"] = "USER_NOT_FOUND";
|
|
79
77
|
UserDisabledByIdStatus["INTERNAL_ERROR"] = "INTERNAL_ERROR";
|
|
80
78
|
})(UserDisabledByIdStatus || (exports.UserDisabledByIdStatus = UserDisabledByIdStatus = {}));
|
|
81
79
|
var UserDisabledByEmailStatus;
|
|
@@ -83,43 +81,46 @@ var UserDisabledByEmailStatus;
|
|
|
83
81
|
UserDisabledByEmailStatus["MISSING_USER_ID"] = "MISSING_USER_ID";
|
|
84
82
|
UserDisabledByEmailStatus["ENABLED"] = "ENABLED";
|
|
85
83
|
UserDisabledByEmailStatus["DISABLED"] = "DISABLED";
|
|
86
|
-
UserDisabledByEmailStatus["
|
|
84
|
+
UserDisabledByEmailStatus["USER_NOT_FOUND"] = "USER_NOT_FOUND";
|
|
87
85
|
UserDisabledByEmailStatus["INTERNAL_ERROR"] = "INTERNAL_ERROR";
|
|
88
86
|
})(UserDisabledByEmailStatus || (exports.UserDisabledByEmailStatus = UserDisabledByEmailStatus = {}));
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
87
|
+
class IsUserDisabled {
|
|
88
|
+
static async withId(userId) {
|
|
89
|
+
userId = userId.trim();
|
|
90
|
+
if (!userId || userId === "")
|
|
91
|
+
return UserDisabledByIdStatus.MISSING_USER_ID;
|
|
92
|
+
try {
|
|
93
|
+
const user = await admin.auth().getUser(userId);
|
|
94
|
+
const isUserDisabled = user.disabled;
|
|
95
|
+
return isUserDisabled
|
|
96
|
+
? UserDisabledByIdStatus.DISABLED
|
|
97
|
+
: UserDisabledByIdStatus.ENABLED;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (error.code === "auth/user-not-found") {
|
|
101
|
+
return UserDisabledByIdStatus.USER_NOT_FOUND;
|
|
102
|
+
}
|
|
103
|
+
return UserDisabledByIdStatus.INTERNAL_ERROR;
|
|
103
104
|
}
|
|
104
|
-
return UserDisabledByIdStatus.INTERNAL_ERROR;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
async function isUserDisabledByEmail(email) {
|
|
108
|
-
email = email.trim();
|
|
109
|
-
if (!email)
|
|
110
|
-
return UserDisabledByEmailStatus.MISSING_USER_ID;
|
|
111
|
-
try {
|
|
112
|
-
const user = await admin.auth().getUserByEmail(email);
|
|
113
|
-
const isUserDisabled = user.disabled;
|
|
114
|
-
return isUserDisabled
|
|
115
|
-
? UserDisabledByEmailStatus.DISABLED
|
|
116
|
-
: UserDisabledByEmailStatus.ENABLED;
|
|
117
105
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
106
|
+
static async withEmail(email) {
|
|
107
|
+
email = email.trim();
|
|
108
|
+
if (!email || email === "")
|
|
109
|
+
return UserDisabledByEmailStatus.MISSING_USER_ID;
|
|
110
|
+
try {
|
|
111
|
+
const user = await admin.auth().getUserByEmail(email);
|
|
112
|
+
const isUserDisabled = user.disabled;
|
|
113
|
+
return isUserDisabled
|
|
114
|
+
? UserDisabledByEmailStatus.DISABLED
|
|
115
|
+
: UserDisabledByEmailStatus.ENABLED;
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (error.code === "auth/user-not-found") {
|
|
119
|
+
return UserDisabledByEmailStatus.USER_NOT_FOUND;
|
|
120
|
+
}
|
|
121
|
+
return UserDisabledByEmailStatus.INTERNAL_ERROR;
|
|
121
122
|
}
|
|
122
|
-
return UserDisabledByEmailStatus.INTERNAL_ERROR;
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
+
exports.IsUserDisabled = IsUserDisabled;
|
|
125
126
|
//# sourceMappingURL=is_user_disabled.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is_user_disabled.js","sourceRoot":"","sources":["../../src/auth/is_user_disabled.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"is_user_disabled.js","sourceRoot":"","sources":["../../src/auth/is_user_disabled.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,sDAAwC;AAExC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;IAC1B,KAAK,CAAC,aAAa,EAAE,CAAC;AAC1B,CAAC;AAED,IAAY,sBAMX;AAND,WAAY,sBAAsB;IAC9B,6DAAmC,CAAA;IACnC,6CAAmB,CAAA;IACnB,+CAAqB,CAAA;IACrB,2DAAiC,CAAA;IACjC,2DAAiC,CAAA;AACrC,CAAC,EANW,sBAAsB,sCAAtB,sBAAsB,QAMjC;AAED,IAAY,yBAMX;AAND,WAAY,yBAAyB;IACjC,gEAAmC,CAAA;IACnC,gDAAmB,CAAA;IACnB,kDAAqB,CAAA;IACrB,8DAAiC,CAAA;IACjC,8DAAiC,CAAA;AACrC,CAAC,EANW,yBAAyB,yCAAzB,yBAAyB,QAMpC;AAED,MAAa,cAAc;IACvB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAc;QAC9B,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAEvB,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,EAAE;YAAE,OAAO,sBAAsB,CAAC,eAAe,CAAC;QAE5E,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC;YAErC,OAAO,cAAc;gBACjB,CAAC,CAAC,sBAAsB,CAAC,QAAQ;gBACjC,CAAC,CAAC,sBAAsB,CAAC,OAAO,CAAC;QACzC,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YAClB,IAAI,KAAK,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;gBACvC,OAAO,sBAAsB,CAAC,cAAc,CAAC;YACjD,CAAC;YACD,OAAO,sBAAsB,CAAC,cAAc,CAAC;QACjD,CAAC;IACL,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAa;QAChC,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAErB,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,EAAE;YAAE,OAAO,yBAAyB,CAAC,eAAe,CAAC;QAE7E,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YACtD,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC;YAErC,OAAO,cAAc;gBACjB,CAAC,CAAC,yBAAyB,CAAC,QAAQ;gBACpC,CAAC,CAAC,yBAAyB,CAAC,OAAO,CAAC;QAC5C,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YAClB,IAAI,KAAK,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;gBACvC,OAAO,yBAAyB,CAAC,cAAc,CAAC;YACpD,CAAC;YACD,OAAO,yBAAyB,CAAC,cAAc,CAAC;QACpD,CAAC;IACL,CAAC;CACJ;AAxCD,wCAwCC"}
|
|
@@ -63,9 +63,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
63
63
|
};
|
|
64
64
|
})();
|
|
65
65
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
66
|
-
exports.UserExistsByEmailStatus = exports.UserExistsByIdStatus = void 0;
|
|
67
|
-
exports.isUserExistsById = isUserExistsById;
|
|
68
|
-
exports.isUserExistsByEmail = isUserExistsByEmail;
|
|
66
|
+
exports.IsUserExists = exports.UserExistsByEmailStatus = exports.UserExistsByIdStatus = void 0;
|
|
69
67
|
const admin = __importStar(require("firebase-admin"));
|
|
70
68
|
if (admin.apps.length === 0) {
|
|
71
69
|
admin.initializeApp();
|
|
@@ -74,44 +72,47 @@ var UserExistsByIdStatus;
|
|
|
74
72
|
(function (UserExistsByIdStatus) {
|
|
75
73
|
UserExistsByIdStatus["MISSING_USER_ID"] = "MISSING_USER_ID";
|
|
76
74
|
UserExistsByIdStatus["EXISTS"] = "EXISTS";
|
|
77
|
-
UserExistsByIdStatus["
|
|
75
|
+
UserExistsByIdStatus["USER_NOT_FOUND"] = "USER_NOT_FOUND";
|
|
78
76
|
UserExistsByIdStatus["INTERNAL_ERROR"] = "INTERNAL_ERROR";
|
|
79
77
|
})(UserExistsByIdStatus || (exports.UserExistsByIdStatus = UserExistsByIdStatus = {}));
|
|
80
78
|
var UserExistsByEmailStatus;
|
|
81
79
|
(function (UserExistsByEmailStatus) {
|
|
82
80
|
UserExistsByEmailStatus["MISSING_USER_EMAIL"] = "MISSING_USER_EMAIL";
|
|
83
81
|
UserExistsByEmailStatus["EXISTS"] = "EXISTS";
|
|
84
|
-
UserExistsByEmailStatus["
|
|
82
|
+
UserExistsByEmailStatus["USER_NOT_FOUND"] = "USER_NOT_FOUND";
|
|
85
83
|
UserExistsByEmailStatus["INTERNAL_ERROR"] = "INTERNAL_ERROR";
|
|
86
84
|
})(UserExistsByEmailStatus || (exports.UserExistsByEmailStatus = UserExistsByEmailStatus = {}));
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
85
|
+
class IsUserExists {
|
|
86
|
+
static async withId(userId) {
|
|
87
|
+
userId = userId.trim();
|
|
88
|
+
if (!userId || userId === "")
|
|
89
|
+
return UserExistsByIdStatus.MISSING_USER_ID;
|
|
90
|
+
try {
|
|
91
|
+
await admin.auth().getUser(userId);
|
|
92
|
+
return UserExistsByIdStatus.EXISTS;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error.code === "auth/user-not-found") {
|
|
96
|
+
return UserExistsByIdStatus.USER_NOT_FOUND;
|
|
97
|
+
}
|
|
98
|
+
return UserExistsByIdStatus.INTERNAL_ERROR;
|
|
98
99
|
}
|
|
99
|
-
return UserExistsByIdStatus.INTERNAL_ERROR;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
async function isUserExistsByEmail(email) {
|
|
103
|
-
email = email.trim();
|
|
104
|
-
if (!email || email === "")
|
|
105
|
-
return UserExistsByEmailStatus.MISSING_USER_EMAIL;
|
|
106
|
-
try {
|
|
107
|
-
await admin.auth().getUserByEmail(email);
|
|
108
|
-
return UserExistsByEmailStatus.EXISTS;
|
|
109
100
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
101
|
+
static async withEmail(email) {
|
|
102
|
+
email = email.trim();
|
|
103
|
+
if (!email || email === "")
|
|
104
|
+
return UserExistsByEmailStatus.MISSING_USER_EMAIL;
|
|
105
|
+
try {
|
|
106
|
+
await admin.auth().getUserByEmail(email);
|
|
107
|
+
return UserExistsByEmailStatus.EXISTS;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (error.code === "auth/user-not-found") {
|
|
111
|
+
return UserExistsByEmailStatus.USER_NOT_FOUND;
|
|
112
|
+
}
|
|
113
|
+
return UserExistsByEmailStatus.INTERNAL_ERROR;
|
|
113
114
|
}
|
|
114
|
-
return UserExistsByEmailStatus.INTERNAL_ERROR;
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
|
+
exports.IsUserExists = IsUserExists;
|
|
117
118
|
//# sourceMappingURL=is_user_exists.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is_user_exists.js","sourceRoot":"","sources":["../../src/auth/is_user_exists.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"is_user_exists.js","sourceRoot":"","sources":["../../src/auth/is_user_exists.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,sDAAwC;AAExC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;IAC1B,KAAK,CAAC,aAAa,EAAE,CAAC;AAC1B,CAAC;AAED,IAAY,oBAKX;AALD,WAAY,oBAAoB;IAC5B,2DAAmC,CAAA;IACnC,yCAAiB,CAAA;IACjB,yDAAiC,CAAA;IACjC,yDAAiC,CAAA;AACrC,CAAC,EALW,oBAAoB,oCAApB,oBAAoB,QAK/B;AAED,IAAY,uBAKX;AALD,WAAY,uBAAuB;IAC/B,oEAAyC,CAAA;IACzC,4CAAiB,CAAA;IACjB,4DAAiC,CAAA;IACjC,4DAAiC,CAAA;AACrC,CAAC,EALW,uBAAuB,uCAAvB,uBAAuB,QAKlC;AAED,MAAa,YAAY;IACrB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAc;QAC9B,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAEvB,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,EAAE;YAAE,OAAO,oBAAoB,CAAC,eAAe,CAAC;QAE1E,IAAI,CAAC;YACD,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAEnC,OAAO,oBAAoB,CAAC,MAAM,CAAC;QACvC,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YAClB,IAAI,KAAK,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;gBACvC,OAAO,oBAAoB,CAAC,cAAc,CAAC;YAC/C,CAAC;YACD,OAAO,oBAAoB,CAAC,cAAc,CAAC;QAC/C,CAAC;IACL,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAa;QAChC,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAErB,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,EAAE;YAAE,OAAO,uBAAuB,CAAC,kBAAkB,CAAC;QAE9E,IAAI,CAAC;YACD,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAEzC,OAAO,uBAAuB,CAAC,MAAM,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YAClB,IAAI,KAAK,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;gBACvC,OAAO,uBAAuB,CAAC,cAAc,CAAC;YAClD,CAAC;YACD,OAAO,uBAAuB,CAAC,cAAc,CAAC;QAClD,CAAC;IACL,CAAC;CACJ;AAlCD,oCAkCC"}
|
package/lib/auth/otp.js
CHANGED
|
@@ -62,34 +62,101 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
62
62
|
return result;
|
|
63
63
|
};
|
|
64
64
|
})();
|
|
65
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
66
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
67
|
+
};
|
|
65
68
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
66
|
-
exports.
|
|
69
|
+
exports.Otp = exports.GetOTPStatus = exports.GenerateStatus = void 0;
|
|
70
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
67
71
|
const admin = __importStar(require("firebase-admin"));
|
|
72
|
+
const config_1 = require("../common/config");
|
|
68
73
|
if (admin.apps.length === 0) {
|
|
69
74
|
admin.initializeApp();
|
|
70
75
|
}
|
|
71
|
-
var
|
|
72
|
-
(function (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
76
|
+
var GenerateStatus;
|
|
77
|
+
(function (GenerateStatus) {
|
|
78
|
+
GenerateStatus["MISSING_OTP_CONFIG"] = "MISSING_OTP_CONFIG";
|
|
79
|
+
GenerateStatus["SUCCESS"] = "SUCCESS";
|
|
80
|
+
})(GenerateStatus || (exports.GenerateStatus = GenerateStatus = {}));
|
|
81
|
+
var GetOTPStatus;
|
|
82
|
+
(function (GetOTPStatus) {
|
|
83
|
+
GetOTPStatus["MISSING_OTP_CONFIG"] = "MISSING_OTP_CONFIG";
|
|
84
|
+
GetOTPStatus["OTP_NOT_FOUND"] = "OTP_NOT_FOUND";
|
|
85
|
+
GetOTPStatus["OTP_FOUND"] = "OTP_FOUND";
|
|
86
|
+
})(GetOTPStatus || (exports.GetOTPStatus = GetOTPStatus = {}));
|
|
87
|
+
class Otp {
|
|
88
|
+
static async generate(userId, type) {
|
|
89
|
+
const config = (0, config_1.appInitialize)();
|
|
90
|
+
const otp = config.otp;
|
|
91
|
+
if (otp.collection === undefined)
|
|
92
|
+
return GenerateStatus.MISSING_OTP_CONFIG;
|
|
93
|
+
const now = Date.now();
|
|
94
|
+
const otpCode = OTPUtils.generate();
|
|
95
|
+
const hashOtp = OTPUtils.hash(otpCode);
|
|
96
|
+
await admin.firestore().collection(otp.collection).add({
|
|
97
|
+
__fbs__user_id: userId,
|
|
98
|
+
__fbs__created_at: now,
|
|
99
|
+
__fbs__otp_type: type,
|
|
100
|
+
__fbs__otp: hashOtp,
|
|
101
|
+
});
|
|
102
|
+
return GenerateStatus.SUCCESS;
|
|
103
|
+
}
|
|
104
|
+
static async get(userId, type) {
|
|
105
|
+
const config = (0, config_1.appInitialize)();
|
|
106
|
+
const otp = config.otp;
|
|
107
|
+
if (otp.collection === undefined)
|
|
108
|
+
return { status: GetOTPStatus.MISSING_OTP_CONFIG };
|
|
109
|
+
const snapshot = await admin.firestore()
|
|
110
|
+
.collection(otp.collection)
|
|
111
|
+
.where("__fbs__user_id", "==", userId)
|
|
112
|
+
.where("__fbs__otp_type", "==", type)
|
|
113
|
+
.orderBy("__fbs__created_at", "desc")
|
|
114
|
+
.limit(1)
|
|
115
|
+
.get();
|
|
116
|
+
if (snapshot.docs.length === 0)
|
|
117
|
+
return { status: GetOTPStatus.OTP_NOT_FOUND };
|
|
118
|
+
const doc = snapshot.docs[0];
|
|
119
|
+
const data = doc?.data();
|
|
120
|
+
const otpCode = data?.__fbs__otp;
|
|
121
|
+
return { status: GetOTPStatus.MISSING_OTP_CONFIG, otp: otpCode };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
exports.Otp = Otp;
|
|
125
|
+
class OTPUtils {
|
|
126
|
+
static generate() {
|
|
127
|
+
while (true) {
|
|
128
|
+
const buffer = crypto_1.default.randomBytes(4);
|
|
129
|
+
const number = buffer.readUInt32BE();
|
|
130
|
+
const otp = (number % 1000000).toString().padStart(6, '0');
|
|
131
|
+
if (this.hasAllIdenticalDigits(otp))
|
|
132
|
+
continue;
|
|
133
|
+
if (this.hasRepeatingPattern(otp))
|
|
134
|
+
continue;
|
|
135
|
+
if (this.hasMoreThanThreeConsecutiveIdenticalDigits(otp))
|
|
136
|
+
continue;
|
|
137
|
+
return otp;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
static hash(otp) {
|
|
141
|
+
return crypto_1.default.createHash('sha256').update(otp).digest('hex');
|
|
142
|
+
}
|
|
143
|
+
static hasAllIdenticalDigits(str) {
|
|
144
|
+
return /^(\d)\1{5}$/.test(str);
|
|
145
|
+
}
|
|
146
|
+
static hasMoreThanThreeConsecutiveIdenticalDigits(str) {
|
|
147
|
+
return /(\d)\1{3,}/.test(str);
|
|
148
|
+
}
|
|
149
|
+
static hasRepeatingPattern(str) {
|
|
150
|
+
const half = str.slice(0, 3);
|
|
151
|
+
if (half.repeat(2) === str)
|
|
152
|
+
return true;
|
|
153
|
+
const pairs = str.match(/(..)/g);
|
|
154
|
+
if (pairs && pairs.length === 3 && new Set(pairs).size === 1)
|
|
155
|
+
return true;
|
|
156
|
+
const mirror = half + half.split('').reverse().join('');
|
|
157
|
+
if (str === mirror)
|
|
158
|
+
return true;
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
95
162
|
//# sourceMappingURL=otp.js.map
|
package/lib/auth/otp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otp.js","sourceRoot":"","sources":["../../src/auth/otp.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG
|
|
1
|
+
{"version":3,"file":"otp.js","sourceRoot":"","sources":["../../src/auth/otp.ts"],"names":[],"mappings":"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"}
|