@mxpicture/gcp-functions 0.1.0
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 +38 -0
- package/dist/cjs/FunctionHandlers.js +18 -0
- package/dist/cjs/api/IApi.js +52 -0
- package/dist/cjs/common/firebase.js +174 -0
- package/dist/cjs/common/http.js +147 -0
- package/dist/cjs/common/types.common.js +30 -0
- package/dist/cjs/handler/HttpHandler.js +41 -0
- package/dist/cjs/handler/IHttpHandlerItem.js +169 -0
- package/dist/cjs/index.js +42 -0
- package/dist/cjs/lib.js +25 -0
- package/dist/cjs/package.js +21 -0
- package/dist/cjs/store/IStore.js +107 -0
- package/dist/cjs/store/types.store.js +15 -0
- package/dist/esm/FunctionHandlers.js +18 -0
- package/dist/esm/api/IApi.js +52 -0
- package/dist/esm/common/firebase.js +174 -0
- package/dist/esm/common/http.js +147 -0
- package/dist/esm/common/types.common.js +30 -0
- package/dist/esm/handler/HttpHandler.js +41 -0
- package/dist/esm/handler/IHttpHandlerItem.js +169 -0
- package/dist/esm/index.js +42 -0
- package/dist/esm/lib.js +25 -0
- package/dist/esm/package.js +21 -0
- package/dist/esm/store/IStore.js +107 -0
- package/dist/esm/store/types.store.js +15 -0
- package/dist/types/FunctionHandlers.d.ts +12 -0
- package/dist/types/api/IApi.d.ts +27 -0
- package/dist/types/common/firebase.d.ts +11 -0
- package/dist/types/common/http.d.ts +20 -0
- package/dist/types/common/types.common.d.ts +31 -0
- package/dist/types/handler/HttpHandler.d.ts +15 -0
- package/dist/types/handler/IHttpHandlerItem.d.ts +23 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/lib.d.ts +11 -0
- package/dist/types/package.d.ts +1 -0
- package/dist/types/store/IStore.d.ts +25 -0
- package/dist/types/store/types.store.d.ts +23 -0
- package/package.json +74 -0
|
@@ -0,0 +1,42 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
19
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
20
|
+
};
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
__exportStar(require("./lib"), exports);
|
|
40
|
+
// A default export can help some consumers using require()
|
|
41
|
+
const _all = __importStar(require("./lib"));
|
|
42
|
+
exports.default = _all;
|
package/dist/cjs/lib.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
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("./FunctionHandlers"), exports);
|
|
18
|
+
__exportStar(require("./handler/IHttpHandlerItem"), exports);
|
|
19
|
+
__exportStar(require("./handler/HttpHandler"), exports);
|
|
20
|
+
__exportStar(require("./common/firebase"), exports);
|
|
21
|
+
__exportStar(require("./common/http"), exports);
|
|
22
|
+
__exportStar(require("./common/types.common"), exports);
|
|
23
|
+
__exportStar(require("./api/IApi"), exports);
|
|
24
|
+
__exportStar(require("./store/IStore"), exports);
|
|
25
|
+
__exportStar(require("./store/types.store"), exports);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
|
3
|
+
/// <reference path="./types/express.d.ts" />
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
16
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
// Re-export your public types/exports so this file becomes the root .d.ts for the package.
|
|
20
|
+
// Adjust the relative path if your source layout differs.
|
|
21
|
+
__exportStar(require("./lib"), exports);
|
|
@@ -0,0 +1,107 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.IStore = exports.convertDocObject = void 0;
|
|
37
|
+
const firebase_js_1 = require("../common/firebase.js");
|
|
38
|
+
const uuid = __importStar(require("short-uuid"));
|
|
39
|
+
const convertDocObject = (doc) => {
|
|
40
|
+
if (typeof doc.data !== "function")
|
|
41
|
+
return doc;
|
|
42
|
+
return {
|
|
43
|
+
...doc.data(),
|
|
44
|
+
createTime: doc.createTime,
|
|
45
|
+
updateTime: doc.updateTime,
|
|
46
|
+
id: doc.id,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
exports.convertDocObject = convertDocObject;
|
|
50
|
+
class IStore {
|
|
51
|
+
constructor(collectionName) {
|
|
52
|
+
this.collectionName = collectionName;
|
|
53
|
+
}
|
|
54
|
+
db() {
|
|
55
|
+
if (!this._db)
|
|
56
|
+
this._db = firebase_js_1.db
|
|
57
|
+
.collection(`picpad.${this.collectionName}`)
|
|
58
|
+
.withConverter(this.createConverter());
|
|
59
|
+
return this._db;
|
|
60
|
+
}
|
|
61
|
+
async query(p) {
|
|
62
|
+
const snapshot = p && p.parentId
|
|
63
|
+
? await this.refByParent(p.parentId).get()
|
|
64
|
+
: await this.db().get();
|
|
65
|
+
return snapshot.docs.map((exports.convertDocObject));
|
|
66
|
+
}
|
|
67
|
+
async count(p) {
|
|
68
|
+
const snapshot = p && p.parentId
|
|
69
|
+
? await this.refByParent(p.parentId).count().get()
|
|
70
|
+
: await this.db().count().get();
|
|
71
|
+
return snapshot.data().count;
|
|
72
|
+
}
|
|
73
|
+
ref(id) {
|
|
74
|
+
return this.db().doc(id);
|
|
75
|
+
}
|
|
76
|
+
async get(id) {
|
|
77
|
+
const snapshot = await this.ref(id).get();
|
|
78
|
+
if (!snapshot.exists)
|
|
79
|
+
throw new Error(`Id ${id} does not exist`);
|
|
80
|
+
return (0, exports.convertDocObject)(snapshot);
|
|
81
|
+
}
|
|
82
|
+
async exists(id) {
|
|
83
|
+
return (await this.ref(id).get()).exists;
|
|
84
|
+
}
|
|
85
|
+
async create(doc) {
|
|
86
|
+
doc.id = uuid.generate();
|
|
87
|
+
const ref = this.ref(doc.id);
|
|
88
|
+
await ref.set(doc);
|
|
89
|
+
return this.get(doc.id);
|
|
90
|
+
}
|
|
91
|
+
async update(id, doc) {
|
|
92
|
+
const entry = this.ref(id);
|
|
93
|
+
await entry.update({ ...doc });
|
|
94
|
+
return this.get(id);
|
|
95
|
+
}
|
|
96
|
+
async delete(...ids) {
|
|
97
|
+
await Promise.all(ids.map((id) => this.ref(id).delete()));
|
|
98
|
+
}
|
|
99
|
+
async deleteByParent(parentId) {
|
|
100
|
+
const snapshot = await this.refByParent(parentId).get();
|
|
101
|
+
await this.delete(...snapshot.docs.map((doc) => doc.id));
|
|
102
|
+
}
|
|
103
|
+
refByParent(parentId) {
|
|
104
|
+
return this.db().where("parentId", "==", parentId);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
exports.IStore = IStore;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.storePersistSchema = exports.storeBaseSchema = exports.storePersistSchemaShape = exports.storeBaseSchemaShape = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.storeBaseSchemaShape = {
|
|
6
|
+
id: zod_1.z.string().optional(),
|
|
7
|
+
createTime: zod_1.z.date().optional(),
|
|
8
|
+
updateTime: zod_1.z.date().optional(),
|
|
9
|
+
};
|
|
10
|
+
exports.storePersistSchemaShape = {
|
|
11
|
+
...exports.storeBaseSchemaShape,
|
|
12
|
+
id: zod_1.z.string(),
|
|
13
|
+
};
|
|
14
|
+
exports.storeBaseSchema = zod_1.z.object(exports.storeBaseSchemaShape);
|
|
15
|
+
exports.storePersistSchema = zod_1.z.object(exports.storePersistSchemaShape);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FunctionHandlers = void 0;
|
|
4
|
+
class FunctionHandlers {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.items = {};
|
|
7
|
+
}
|
|
8
|
+
add(handler) {
|
|
9
|
+
this.items[handler.name] = handler;
|
|
10
|
+
}
|
|
11
|
+
functions() {
|
|
12
|
+
const result = {};
|
|
13
|
+
for (const [key, item] of Object.entries(this.items))
|
|
14
|
+
result[key] = item.setup();
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.FunctionHandlers = FunctionHandlers;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IApi = void 0;
|
|
4
|
+
const zod_meta_1 = require("@mxpicture/zod-meta");
|
|
5
|
+
class IApi {
|
|
6
|
+
constructor(store, shape) {
|
|
7
|
+
this.store = store;
|
|
8
|
+
this.shape = shape;
|
|
9
|
+
}
|
|
10
|
+
metaItems() {
|
|
11
|
+
return new zod_meta_1.Meta(this.shape).items();
|
|
12
|
+
}
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
14
|
+
async create(doc, params) {
|
|
15
|
+
const storeDoc = await this.store.create(doc);
|
|
16
|
+
return this.fromStore(storeDoc);
|
|
17
|
+
}
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
19
|
+
async get(id, params) {
|
|
20
|
+
const storeDoc = await this.store.get(id);
|
|
21
|
+
return this.fromStore(storeDoc);
|
|
22
|
+
}
|
|
23
|
+
async query(params) {
|
|
24
|
+
const storeDocs = await this.store.query(params);
|
|
25
|
+
return await Promise.all(storeDocs.map((s) => this.fromStore(s)));
|
|
26
|
+
}
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
|
+
async count(params) {
|
|
29
|
+
return this.store.count();
|
|
30
|
+
}
|
|
31
|
+
async update(id, doc,
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
33
|
+
params) {
|
|
34
|
+
let storeDoc = await this.toStore(doc);
|
|
35
|
+
storeDoc = await this.store.update(id, storeDoc);
|
|
36
|
+
return this.fromStore(storeDoc);
|
|
37
|
+
}
|
|
38
|
+
async updatePartial(id, doc) {
|
|
39
|
+
const storeDoc = await this.toStorePartial(doc);
|
|
40
|
+
await this.store.update(id, storeDoc);
|
|
41
|
+
return this.get(id);
|
|
42
|
+
}
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
44
|
+
async delete(id, params) {
|
|
45
|
+
await this.store.delete(id);
|
|
46
|
+
}
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
48
|
+
async exists(id, params) {
|
|
49
|
+
return this.store.exists(id);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.IApi = IApi;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.round = exports.verifyConnectionToken = exports.sessionLogout = exports.sessionLogin = exports.verifyAuthAll = exports.verifySessionCookie = exports.verifyToken = exports.extractToken = exports.db = exports.app = void 0;
|
|
4
|
+
const auth_1 = require("firebase-admin/auth");
|
|
5
|
+
const firestore_1 = require("firebase-admin/firestore");
|
|
6
|
+
const app_1 = require("firebase-admin/app");
|
|
7
|
+
exports.app = (0, app_1.initializeApp)();
|
|
8
|
+
exports.db = (0, firestore_1.getFirestore)();
|
|
9
|
+
const extractToken = (request) => {
|
|
10
|
+
const auth = request.headers["authorization"];
|
|
11
|
+
if (!auth)
|
|
12
|
+
return;
|
|
13
|
+
// Read the ID Token from the Authorization header.
|
|
14
|
+
if (auth && auth.startsWith("Bearer "))
|
|
15
|
+
return auth.split("Bearer ")[1];
|
|
16
|
+
// Read the ID Token from cookie.
|
|
17
|
+
if (request.cookies)
|
|
18
|
+
return request.cookies.__session;
|
|
19
|
+
return;
|
|
20
|
+
};
|
|
21
|
+
exports.extractToken = extractToken;
|
|
22
|
+
// Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
|
|
23
|
+
// The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
|
|
24
|
+
// `Authorization: Bearer <Firebase ID Token>`.
|
|
25
|
+
// when decoded successfully, the ID Token content will be added as `request.user`.
|
|
26
|
+
const verifyToken = (request, response, next) => {
|
|
27
|
+
const token = (0, exports.extractToken)(request);
|
|
28
|
+
if (!token) {
|
|
29
|
+
response
|
|
30
|
+
.status(401)
|
|
31
|
+
.json({ status: "unauthorized", message: "Unauthorized" });
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
(0, auth_1.getAuth)()
|
|
35
|
+
.verifyIdToken(token)
|
|
36
|
+
.then((decodedIdToken) => {
|
|
37
|
+
// Only process if the user just signed in in the last 5 minutes.
|
|
38
|
+
if (Date.now() / 1000 - decodedIdToken.auth_time >= 5 * 60)
|
|
39
|
+
return response.status(401).json({
|
|
40
|
+
status: "unauthorized",
|
|
41
|
+
message: "Recent sign in required!",
|
|
42
|
+
});
|
|
43
|
+
request.user = decodedIdToken;
|
|
44
|
+
request.headers["x-id-token"] = token;
|
|
45
|
+
return next();
|
|
46
|
+
}, (error) => {
|
|
47
|
+
response.status(401).json({
|
|
48
|
+
status: "unauthorized",
|
|
49
|
+
message: JSON.stringify(error),
|
|
50
|
+
});
|
|
51
|
+
})
|
|
52
|
+
.catch((error) => {
|
|
53
|
+
response.status(401).json({
|
|
54
|
+
status: "unauthorized",
|
|
55
|
+
message: `Error while verifying Firebase ID token: ${error}`,
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
exports.verifyToken = verifyToken;
|
|
60
|
+
const verifySessionCookie = (request, response, next) => {
|
|
61
|
+
const sessionCookie =
|
|
62
|
+
// request.cookies.session ||
|
|
63
|
+
// request.cookies.zsession ||
|
|
64
|
+
request.cookies.__session || request.headers.zsession || "";
|
|
65
|
+
// Verify the session cookie. In this case an additional check is added to detect
|
|
66
|
+
// if the user's Firebase session was revoked, user deleted/disabled, etc.
|
|
67
|
+
(0, auth_1.getAuth)()
|
|
68
|
+
.verifySessionCookie(sessionCookie, true /** checkRevoked */)
|
|
69
|
+
.then(() => {
|
|
70
|
+
next();
|
|
71
|
+
}, (error) => {
|
|
72
|
+
response.status(401).json({
|
|
73
|
+
status: "unauthorized",
|
|
74
|
+
message: JSON.stringify(error),
|
|
75
|
+
});
|
|
76
|
+
})
|
|
77
|
+
.catch((error) => {
|
|
78
|
+
response.status(401).json({
|
|
79
|
+
status: "unauthorized",
|
|
80
|
+
message: JSON.stringify(error),
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
exports.verifySessionCookie = verifySessionCookie;
|
|
85
|
+
const verifyAuthAll = (token) => {
|
|
86
|
+
return (request, response, next) => {
|
|
87
|
+
const t = token();
|
|
88
|
+
// connection token
|
|
89
|
+
const id = request.headers["x-connection-token"];
|
|
90
|
+
if (typeof id === "string") {
|
|
91
|
+
if (id === t)
|
|
92
|
+
return next();
|
|
93
|
+
return response.status(401).json({
|
|
94
|
+
status: "unauthorized",
|
|
95
|
+
message: "",
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
// message connection token
|
|
99
|
+
if ((0, exports.extractToken)(request))
|
|
100
|
+
return (0, exports.verifyToken)(request, response, next);
|
|
101
|
+
// session cookie
|
|
102
|
+
return (0, exports.verifySessionCookie)(request, response, next);
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
exports.verifyAuthAll = verifyAuthAll;
|
|
106
|
+
const sessionLogin = (request, response) => {
|
|
107
|
+
// Get the ID token passed and the CSRF token.
|
|
108
|
+
const idToken = `${request.headers["x-id-token"]}`;
|
|
109
|
+
// Set session expiration to 5 days.
|
|
110
|
+
const expiresIn = 60 * 60 * 24 * 5 * 1000;
|
|
111
|
+
// Create the session cookie. This will also verify the ID token in the process.
|
|
112
|
+
// The session cookie will have the same claims as the ID token.
|
|
113
|
+
// To only allow session cookie setting on recent sign-in, auth_time in ID token
|
|
114
|
+
// can be checked to ensure user was recently signed in before creating a session cookie.
|
|
115
|
+
(0, auth_1.getAuth)()
|
|
116
|
+
.createSessionCookie(idToken, { expiresIn })
|
|
117
|
+
.then((sessionCookie) => {
|
|
118
|
+
// Set cookie policy for session cookie.
|
|
119
|
+
// cloud functions will only allow __session (issue only deployed)
|
|
120
|
+
response.cookie("__session", sessionCookie, {
|
|
121
|
+
maxAge: expiresIn,
|
|
122
|
+
httpOnly: true,
|
|
123
|
+
secure: true,
|
|
124
|
+
});
|
|
125
|
+
// const now = new Date();
|
|
126
|
+
// const zsession =
|
|
127
|
+
// "zsession=" +
|
|
128
|
+
// sessionCookie +
|
|
129
|
+
// "; expires=" +
|
|
130
|
+
// now.toUTCString() +
|
|
131
|
+
// "; path=/";
|
|
132
|
+
response.end(JSON.stringify({
|
|
133
|
+
status: "success",
|
|
134
|
+
// zsession: zsession,
|
|
135
|
+
}));
|
|
136
|
+
}, (error) => {
|
|
137
|
+
response.status(401).json({
|
|
138
|
+
status: "unauthorized",
|
|
139
|
+
message: JSON.stringify(error),
|
|
140
|
+
});
|
|
141
|
+
})
|
|
142
|
+
.catch((error) => {
|
|
143
|
+
response.status(401).json({
|
|
144
|
+
status: "unauthorized",
|
|
145
|
+
message: JSON.stringify(error),
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
exports.sessionLogin = sessionLogin;
|
|
150
|
+
const sessionLogout = (request, response) => {
|
|
151
|
+
response.clearCookie("session");
|
|
152
|
+
response.clearCookie("zsession");
|
|
153
|
+
response.clearCookie("__session");
|
|
154
|
+
};
|
|
155
|
+
exports.sessionLogout = sessionLogout;
|
|
156
|
+
const verifyConnectionToken = (token) => {
|
|
157
|
+
return async (request, response, next) => {
|
|
158
|
+
const id = request.headers["x-connection-token"];
|
|
159
|
+
if (id === token()) {
|
|
160
|
+
next();
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
response.status(401).json({
|
|
164
|
+
status: "unauthorized",
|
|
165
|
+
message: "",
|
|
166
|
+
});
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
exports.verifyConnectionToken = verifyConnectionToken;
|
|
170
|
+
const round = (value, digits = 3) => {
|
|
171
|
+
const factor = Math.pow(10, digits);
|
|
172
|
+
return Math.round(value * factor) / factor;
|
|
173
|
+
};
|
|
174
|
+
exports.round = round;
|
|
@@ -0,0 +1,147 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.fixRequestBody = exports.hasBody = exports.contentstream = void 0;
|
|
40
|
+
const querystring = __importStar(require("querystring"));
|
|
41
|
+
const zlib_1 = require("zlib");
|
|
42
|
+
const zlib = __importStar(require("zlib"));
|
|
43
|
+
const http_errors_1 = __importDefault(require("http-errors"));
|
|
44
|
+
// export const handleErrorMessage = (
|
|
45
|
+
// response: express.Response,
|
|
46
|
+
// error: unknown,
|
|
47
|
+
// code: number = StatusCodes.BAD_REQUEST,
|
|
48
|
+
// ) => {
|
|
49
|
+
// // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
+
// const ae = error as any;
|
|
51
|
+
// const result = { message: "" };
|
|
52
|
+
// if (error instanceof Error) result.message = error.message;
|
|
53
|
+
// else if (typeof error === "string") result.message = error;
|
|
54
|
+
// else if (ae.message) result.message = ae.message;
|
|
55
|
+
// else if (ae.payload) {
|
|
56
|
+
// if (ae.payload.message && typeof ae.payload.message === "string")
|
|
57
|
+
// result.message = ae.payload.message;
|
|
58
|
+
// else if (typeof ae.payload === "string") result.message = ae.payload;
|
|
59
|
+
// } else result.message = "unknown";
|
|
60
|
+
// return response.status(code).json(result);
|
|
61
|
+
// };
|
|
62
|
+
const hasBrotliSupport = "createBrotliDecompress" in zlib;
|
|
63
|
+
/**
|
|
64
|
+
* Get the content stream of the request.
|
|
65
|
+
*
|
|
66
|
+
* @param {object} req
|
|
67
|
+
* @param {function} debug
|
|
68
|
+
* @param {boolean} [inflate=true]
|
|
69
|
+
* @return {object}
|
|
70
|
+
* @api private
|
|
71
|
+
*/
|
|
72
|
+
const contentstream = (req, inflate, debug = console) => {
|
|
73
|
+
const encoding = (req.headers["content-encoding"] || "identity").toLowerCase();
|
|
74
|
+
// const length = req.headers["content-length"];
|
|
75
|
+
let stream;
|
|
76
|
+
debug?.log('content-encoding "%s"', encoding);
|
|
77
|
+
if (inflate === false && encoding !== "identity") {
|
|
78
|
+
throw (0, http_errors_1.default)(415, "content encoding unsupported", {
|
|
79
|
+
encoding: encoding,
|
|
80
|
+
type: "encoding.unsupported",
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
switch (encoding) {
|
|
84
|
+
case "deflate":
|
|
85
|
+
stream = (0, zlib_1.createInflate)();
|
|
86
|
+
debug?.log("inflate body");
|
|
87
|
+
req.pipe(stream);
|
|
88
|
+
break;
|
|
89
|
+
case "gzip":
|
|
90
|
+
stream = (0, zlib_1.createGunzip)();
|
|
91
|
+
debug?.log("gunzip body");
|
|
92
|
+
req.pipe(stream);
|
|
93
|
+
break;
|
|
94
|
+
case "identity":
|
|
95
|
+
stream = req;
|
|
96
|
+
// stream.length = length;
|
|
97
|
+
break;
|
|
98
|
+
case "br":
|
|
99
|
+
if (hasBrotliSupport) {
|
|
100
|
+
stream = (0, zlib_1.createBrotliDecompress)();
|
|
101
|
+
debug?.log("brotli decompress body");
|
|
102
|
+
req.pipe(stream);
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
if (stream === undefined) {
|
|
107
|
+
throw (0, http_errors_1.default)(415, 'unsupported content encoding "' + encoding + '"', {
|
|
108
|
+
encoding: encoding,
|
|
109
|
+
type: "encoding.unsupported",
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return stream;
|
|
113
|
+
};
|
|
114
|
+
exports.contentstream = contentstream;
|
|
115
|
+
const hasBody = (request) => {
|
|
116
|
+
const contentType = request.headers["content-type"];
|
|
117
|
+
return contentType
|
|
118
|
+
? contentType.includes("application/json") ||
|
|
119
|
+
contentType.includes("+json") ||
|
|
120
|
+
contentType.includes("application/x-www-form-urlencoded")
|
|
121
|
+
: false;
|
|
122
|
+
};
|
|
123
|
+
exports.hasBody = hasBody;
|
|
124
|
+
/**
|
|
125
|
+
* Fix proxied body if bodyParser is involved.
|
|
126
|
+
*/
|
|
127
|
+
const fixRequestBody = (proxyReq, requestBody) => {
|
|
128
|
+
if (!requestBody) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const contentType = proxyReq.getHeader("Content-Type");
|
|
132
|
+
const writeBody = (bodyData) => {
|
|
133
|
+
// deepcode ignore ContentLengthInCode: bodyParser fix
|
|
134
|
+
proxyReq.setHeader("Content-Length", `'${Buffer.byteLength(bodyData)}'`);
|
|
135
|
+
proxyReq.write(bodyData);
|
|
136
|
+
};
|
|
137
|
+
if (contentType &&
|
|
138
|
+
(contentType.includes("application/json") || contentType.includes("+json"))) {
|
|
139
|
+
writeBody(JSON.stringify(requestBody));
|
|
140
|
+
}
|
|
141
|
+
if (contentType &&
|
|
142
|
+
contentType.includes("application/x-www-form-urlencoded") &&
|
|
143
|
+
!Array.isArray(requestBody)) {
|
|
144
|
+
writeBody(querystring.stringify(requestBody));
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
exports.fixRequestBody = fixRequestBody;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.castHttpError = exports.PrimitiveType = exports.HttpMethod = exports.HttpProtocol = void 0;
|
|
4
|
+
var HttpProtocol;
|
|
5
|
+
(function (HttpProtocol) {
|
|
6
|
+
HttpProtocol["http"] = "http";
|
|
7
|
+
HttpProtocol["https"] = "https";
|
|
8
|
+
})(HttpProtocol || (exports.HttpProtocol = HttpProtocol = {}));
|
|
9
|
+
var HttpMethod;
|
|
10
|
+
(function (HttpMethod) {
|
|
11
|
+
HttpMethod["POST"] = "POST";
|
|
12
|
+
HttpMethod["PATCH"] = "PATCH";
|
|
13
|
+
HttpMethod["PUT"] = "PUT";
|
|
14
|
+
HttpMethod["GET"] = "GET";
|
|
15
|
+
HttpMethod["DELETE"] = "DELETE";
|
|
16
|
+
})(HttpMethod || (exports.HttpMethod = HttpMethod = {}));
|
|
17
|
+
var PrimitiveType;
|
|
18
|
+
(function (PrimitiveType) {
|
|
19
|
+
PrimitiveType["string"] = "string";
|
|
20
|
+
PrimitiveType["number"] = "number";
|
|
21
|
+
PrimitiveType["boolean"] = "boolean";
|
|
22
|
+
})(PrimitiveType || (exports.PrimitiveType = PrimitiveType = {}));
|
|
23
|
+
const castHttpError = (error) => {
|
|
24
|
+
if (!error.message || typeof error.message !== "string")
|
|
25
|
+
return;
|
|
26
|
+
if (error.context && typeof error.message !== "string")
|
|
27
|
+
return;
|
|
28
|
+
return { message: error.message, context: error.context };
|
|
29
|
+
};
|
|
30
|
+
exports.castHttpError = castHttpError;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.HttpHandler = void 0;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
const cookie_parser_1 = __importDefault(require("cookie-parser"));
|
|
9
|
+
const cors_1 = __importDefault(require("cors"));
|
|
10
|
+
const https_1 = require("firebase-functions/v2/https");
|
|
11
|
+
// export interface HandlerEnv {
|
|
12
|
+
// connectionToken: () => string;
|
|
13
|
+
// }
|
|
14
|
+
class HttpHandler {
|
|
15
|
+
constructor(name) {
|
|
16
|
+
this.name = name;
|
|
17
|
+
this.corsAllowList = [];
|
|
18
|
+
this.items = [];
|
|
19
|
+
this.exp = (0, express_1.default)();
|
|
20
|
+
}
|
|
21
|
+
add(...items) {
|
|
22
|
+
this.items.push(...items);
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
baseSetup() {
|
|
26
|
+
this.exp.use((0, cors_1.default)({ credentials: true, origin: true }));
|
|
27
|
+
this.exp.use((0, cookie_parser_1.default)());
|
|
28
|
+
this.exp.disable("x-powered-by");
|
|
29
|
+
// this.exp.use(verifySessionCookie); // todo verify token (maybe connection token)
|
|
30
|
+
}
|
|
31
|
+
setup() {
|
|
32
|
+
this.baseSetup();
|
|
33
|
+
for (const item of this.items)
|
|
34
|
+
item.setup(this.exp);
|
|
35
|
+
return this.createFunction();
|
|
36
|
+
}
|
|
37
|
+
createFunction() {
|
|
38
|
+
return (0, https_1.onRequest)({ cors: [/firebase\.com$/, /web\.app$/] }, this.exp);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.HttpHandler = HttpHandler;
|