fiber-firebase-functions 1.0.2 → 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 +162 -0
- package/lib/auth/otp.js.map +1 -0
- package/lib/auth/reset_password.js +327 -0
- package/lib/auth/reset_password.js.map +1 -0
- package/lib/auth/update_password.js +18 -7
- package/lib/auth/update_password.js.map +1 -1
- package/lib/auth/user.js +44 -32
- package/lib/auth/user.js.map +1 -1
- package/lib/common/config.js +64 -0
- package/lib/common/config.js.map +1 -0
- 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/send_email.js +81 -0
- package/lib/email/send_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/lib/email/templates.js +38 -0
- 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 +19 -6
- 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 +135 -0
- package/src/auth/reset_password.ts +317 -0
- package/src/auth/user.ts +34 -24
- package/src/common/config.ts +84 -0
- 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 +25 -6
- package/src/auth/update_password.ts +0 -211
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
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (C) 2025 Fiber
|
|
4
|
+
*
|
|
5
|
+
* All rights reserved. This script, including its code and logic, is the
|
|
6
|
+
* exclusive property of Fiber. Redistribution, reproduction,
|
|
7
|
+
* or modification of any part of this script is strictly prohibited
|
|
8
|
+
* without prior written permission from Fiber.
|
|
9
|
+
*
|
|
10
|
+
* Conditions of use:
|
|
11
|
+
* - The code may not be copied, duplicated, or used, in whole or in part,
|
|
12
|
+
* for any purpose without explicit authorization.
|
|
13
|
+
* - Redistribution of this code, with or without modification, is not
|
|
14
|
+
* permitted unless expressly agreed upon by Fiber.
|
|
15
|
+
* - The name "Fiber" and any associated branding, logos, or
|
|
16
|
+
* trademarks may not be used to endorse or promote derived products
|
|
17
|
+
* or services without prior written approval.
|
|
18
|
+
*
|
|
19
|
+
* Disclaimer:
|
|
20
|
+
* THIS SCRIPT AND ITS CODE ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
|
21
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL
|
|
23
|
+
* FIBER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
24
|
+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING BUT NOT LIMITED TO LOSS OF USE,
|
|
25
|
+
* DATA, PROFITS, OR BUSINESS INTERRUPTION) ARISING OUT OF OR RELATED TO THE USE
|
|
26
|
+
* OR INABILITY TO USE THIS SCRIPT, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
*
|
|
28
|
+
* Unauthorized copying or reproduction of this script, in whole or in part,
|
|
29
|
+
* is a violation of applicable intellectual property laws and will result
|
|
30
|
+
* in legal action.
|
|
31
|
+
*/
|
|
32
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
33
|
+
if (k2 === undefined) k2 = k;
|
|
34
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
35
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
36
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
37
|
+
}
|
|
38
|
+
Object.defineProperty(o, k2, desc);
|
|
39
|
+
}) : (function(o, m, k, k2) {
|
|
40
|
+
if (k2 === undefined) k2 = k;
|
|
41
|
+
o[k2] = m[k];
|
|
42
|
+
}));
|
|
43
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
44
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
45
|
+
}) : function(o, v) {
|
|
46
|
+
o["default"] = v;
|
|
47
|
+
});
|
|
48
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
49
|
+
var ownKeys = function(o) {
|
|
50
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
51
|
+
var ar = [];
|
|
52
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
53
|
+
return ar;
|
|
54
|
+
};
|
|
55
|
+
return ownKeys(o);
|
|
56
|
+
};
|
|
57
|
+
return function (mod) {
|
|
58
|
+
if (mod && mod.__esModule) return mod;
|
|
59
|
+
var result = {};
|
|
60
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
61
|
+
__setModuleDefault(result, mod);
|
|
62
|
+
return result;
|
|
63
|
+
};
|
|
64
|
+
})();
|
|
65
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
66
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
67
|
+
};
|
|
68
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
69
|
+
exports.Otp = exports.GetOTPStatus = exports.GenerateStatus = void 0;
|
|
70
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
71
|
+
const admin = __importStar(require("firebase-admin"));
|
|
72
|
+
const config_1 = require("../common/config");
|
|
73
|
+
if (admin.apps.length === 0) {
|
|
74
|
+
admin.initializeApp();
|
|
75
|
+
}
|
|
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
|
+
}
|
|
162
|
+
//# sourceMappingURL=otp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otp.js","sourceRoot":"","sources":["../../src/auth/otp.ts"],"names":[],"mappings":"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"}
|