From 76ffccc0fbbd00d56ab1f783226db8ced3429313 Mon Sep 17 00:00:00 2001 From: kzmaro Date: Thu, 6 Feb 2020 16:30:55 +0900 Subject: [PATCH 01/31] added cors module and fixed status code --- backend/functions/src/index.ts | 104 ++++++++------------------------- frontend/package.json | 1 + frontend/yarn.lock | 35 ++++------- 3 files changed, 35 insertions(+), 105 deletions(-) diff --git a/backend/functions/src/index.ts b/backend/functions/src/index.ts index aad702e..0e78e42 100644 --- a/backend/functions/src/index.ts +++ b/backend/functions/src/index.ts @@ -35,10 +35,12 @@ async function Verification(req: express.Request, resp: express.Response, next: if (token.uid == req.query['uid']) { next(); } else { - resp.send('Error: Id token does not match \'query uid\' '); + console.log('Error: Id token does not match \'query uid\' '); + resp.status(401).send('Unauthorized'); } } catch (exception) { - resp.send('Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again'); + console.log('Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again'); + resp.status(401).send('Unauthorized'); } } @@ -64,74 +66,6 @@ export const DeleteLog = functions.auth.user().onDelete((user) => { return 0; }); -// DBに登録or削除する処理はここまで -// ここから下はswaggerに記載した処理を行う - -export const comments = functions.https.onRequest(Comments); - -async function Comments(req: functions.Request, resp: express.Response) { - console.log('subject_query= ' + req.query['class_name']); - try { - const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').get(); - const records = qss.docs.map((elem: { data: () => void; }) => elem.data()); - console.log(records); - resp.send(JSON.stringify(records)); - } catch (exception) { - resp.send('class not found probably wrong or empty query'); - } -} - -// export const comment = functions.https.onRequest(Comment); -// -// async function Comment(req: functions.Request, resp: express.Response) { -// console.log('subject_query= ' + req.query['class_name'] + ' comment_id=' + req.query['comment_id']); -// try { -// const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').get(); -// const record = qss.docs[req.query['comment_id'] - 1].data(); -// console.log(record); -// resp.send(JSON.stringify(record)); -// } catch (exception) { -// resp.send('class not found probably wrong or empty query'); -// } -// } - - -export const get_class = functions.https.onRequest(Class); - -async function Class(req: functions.Request, resp: express.Response) { - console.log('subject_query= ' + req.query['class_name']); - try { - const documentSnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); - const record = documentSnapshot.data(); - // query:class_name がDBにない場合レスポンスを返さない場合があるのでその処理 - if (!record) { - resp.status(401).send('Unauthorized'); - } - console.log(record); - resp.send(JSON.stringify(record)); - } catch (exception) { - resp.send('class not found probably wrong or empty query'); - } -} - -export const exist_class = functions.https.onRequest(Exist_class); - -async function Exist_class(req: functions.Request, resp: express.Response) { - console.log('subject_query= ' + req.query['class_name']); - // ここだけクエリが空だとError: could not handle the requestがレスポンスで返されるので統一のためにtryで囲む - try { - const doc = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); - if (doc.exists) { - console.log('OK'); - resp.send({ 'status': 'OK' }); - } else { - resp.send('class not found probably wrong or empty query'); - } - } catch (exception) { - resp.send('class not found probably wrong or empty query'); - } -} - // build multiple CRUD interfaces: classData.get('/', async (req: functions.Request, resp: express.Response) => { console.log('subject_query= ' + req.query['class_name']); @@ -139,11 +73,13 @@ classData.get('/', async (req: functions.Request, resp: express.Response) => { const documentSnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); const record = documentSnapshot.data(); if (!record) { - resp.send('class not found probably wrong or empty query'); + console.log('class not found probably wrong or empty query'); + resp.status(404).send('Not Found'); } resp.send(JSON.stringify(record)); } catch (exception) { - resp.send('class not found probably wrong or empty query'); + console.log('class not found probably wrong or empty query'); + resp.status(404).send('Not Found'); } }); @@ -184,9 +120,10 @@ classData.post('/', async (req: functions.Request, resp: express.Response) => { try { await fdb.collection('ClassSummary').doc(body.name).set(data); console.log(data); - resp.send(JSON.stringify({ 'status': 'OK' })); + resp.status(200).send(JSON.stringify({ 'status': 'OK' })); } catch (exception) { - resp.send('An error occurred. Class data cannot add in database'); + console.log('An error occurred. Class data cannot add in database'); + resp.status(500).send('Internal Server Error'); } }); // Expose Express API as a single Cloud Function: @@ -196,12 +133,14 @@ commentData.get('/', async (req: functions.Request, resp: express.Response) => { console.log('subject_query= ' + req.query['class_name'] + ' uid=' + req.query['uid']); try { const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).get(); - if (qss.data() == undefined) { - resp.send('No comment were found match with ' + req.query['class_name'] + ' and this uid'); + if (!qss.data()) { + console.log('No comment were found match with ' + req.query['class_name'] + ' and this uid'); + resp.status(404).send('Not Found'); } - resp.send(JSON.stringify(qss.data())); + resp.status(200).send(JSON.stringify(qss.data())); } catch (exception) { - resp.send('class not found probably wrong or empty query'); + console.log('class not found probably wrong or empty query'); + resp.status(404).send('Not Found'); } }); @@ -230,9 +169,10 @@ commentData.post('/', async (req: functions.Request, resp: express.Response) => try { await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).set(data); console.log(data); - resp.send(JSON.stringify({ 'status': 'OK' })); + resp.status(200).send(JSON.stringify({ 'status': 'OK' })); } catch (exception) { - resp.send('An error occurred. Comment cannot add in database'); + console.log('An error occurred. Comment cannot add in database'); + resp.status(500).send('Internal Server Error'); } }); @@ -241,8 +181,10 @@ commentData.delete('/', async (req: functions.Request, resp: express.Response) = console.log(req.query['class_name'], '+', req.query['uid']); try { await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).delete(); + resp.status(200); } catch (exception) { - resp.send('An error occurred. Comment cannot delete from database'); + console.log('An error occurred. Comment cannot delete from database'); + resp.status(500).send('Internal Server Error'); } }); exports.comment = functions.https.onRequest(commentData); diff --git a/frontend/package.json b/frontend/package.json index 2198ef7..cc47931 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,7 @@ "@fortawesome/vue-fontawesome": "^0.1.6", "axios": "^0.19.0", "core-js": "^2.6.5", + "cors": "^2.8.5", "firebase": "^6.3.1", "firebase-admin": "^8.4.0", "http2": "^3.3.7", diff --git a/frontend/yarn.lock b/frontend/yarn.lock index c3b5640..8ab3ec4 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -3290,6 +3290,14 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + cosmiconfig@^5.0.0: version "5.2.1" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" @@ -7507,22 +7515,6 @@ node-notifier@^5.4.2: shellwords "^0.1.1" which "^1.3.0" -node-pre-gyp@*: - version "0.14.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" - integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4.4.2" - node-pre-gyp@^0.13.0: version "0.13.0" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz#df9ab7b68dd6498137717838e4f92a33fc9daa42" @@ -7672,7 +7664,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -10033,7 +10025,7 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tar@^4, tar@^4.4.2: +tar@^4: version "4.4.13" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== @@ -10594,7 +10586,7 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -vary@~1.1.2: +vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= @@ -10724,11 +10716,6 @@ vuex-class-component@^1.6.0: object.getownpropertydescriptors "^2.0.3" rimraf "^2.6.3" -vuex@^3.0.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.2.tgz#a2863f4005aa73f2587e55c3fadf3f01f69c7d4d" - integrity sha512-ha3jNLJqNhhrAemDXcmMJMKf1Zu4sybMPr9KxJIuOpVcsDQlTBYLLladav2U+g1AvdYDG5Gs0xBTb0M5pXXYFQ== - w3c-hr-time@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" From 3d4cfe95fdda793ff584a69d200c3089158fcb02 Mon Sep 17 00:00:00 2001 From: kzmaro Date: Sat, 8 Feb 2020 15:21:50 +0900 Subject: [PATCH 02/31] =?UTF-8?q?cors=E5=AF=BE=E5=BF=9C=E3=83=A0=E3=83=AA?= =?UTF-8?q?=E3=80=9C=E3=80=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/index.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/backend/functions/src/index.ts b/backend/functions/src/index.ts index 0e78e42..ad85cd0 100644 --- a/backend/functions/src/index.ts +++ b/backend/functions/src/index.ts @@ -12,16 +12,22 @@ const fdb = admin.firestore(); const ref = db.ref('server/account-data/'); // const express = require('express'); -const cors = require('cors'); +const cors = require('cors')({origin: true}); const classData = express(); const commentData = express(); const moment = require('moment'); // Automatically allow cross-origin requests -classData.use(cors({ origin: true })); classData.use(bodyParser.json()); +// cors許可のミドルウェアの実装 +async function allowCrossDomain (req: express.Request, resp: express.Response, next: () => void) { + resp.setHeader('Access-Control-Allow-Origin', '*'); + resp.setHeader('Access-Control-Allow-Methods', '*'); + next(); +} + async function Verification(req: express.Request, resp: express.Response, next: () => void) { // req.headers.authorization のオブジェクトが未定義となるためにts-ignore // @ts-ignore @@ -36,16 +42,20 @@ async function Verification(req: express.Request, resp: express.Response, next: next(); } else { console.log('Error: Id token does not match \'query uid\' '); - resp.status(401).send('Unauthorized'); + cors(req, resp, () => { + resp.status(401).send('Unauthorized'); + }); } } catch (exception) { console.log('Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again'); - resp.status(401).send('Unauthorized'); + await cors(); + cors(req, resp, () => { + resp.status(401).send('Unauthorized') + }); } } - -classData.use(Verification); -commentData.use(Verification); +classData.use(Verification,allowCrossDomain,); +commentData.use(allowCrossDomain,Verification); export const WelcomeLog = functions.auth.user().onCreate((user) => { console.log('Hello ' + user.displayName + ' logged in' + 'called by TS'); From 94206da2c141b80b19091d07acd4d65b6a39b295 Mon Sep 17 00:00:00 2001 From: reud Date: Sat, 8 Feb 2020 16:30:38 +0900 Subject: [PATCH 03/31] arrowAll --- backend/functions/src/index.ts | 283 ++++++++++++++++----------------- 1 file changed, 140 insertions(+), 143 deletions(-) diff --git a/backend/functions/src/index.ts b/backend/functions/src/index.ts index ad85cd0..6e53076 100644 --- a/backend/functions/src/index.ts +++ b/backend/functions/src/index.ts @@ -12,189 +12,186 @@ const fdb = admin.firestore(); const ref = db.ref('server/account-data/'); // const express = require('express'); -const cors = require('cors')({origin: true}); +const cors = require('cors'); const classData = express(); const commentData = express(); const moment = require('moment'); // Automatically allow cross-origin requests +classData.use(cors({ + allowedHeaders: ['Content-Type', 'Authorization'] +})); classData.use(bodyParser.json()); -// cors許可のミドルウェアの実装 -async function allowCrossDomain (req: express.Request, resp: express.Response, next: () => void) { - resp.setHeader('Access-Control-Allow-Origin', '*'); - resp.setHeader('Access-Control-Allow-Methods', '*'); - next(); -} +commentData.use(cors({ + allowedHeaders: ['Content-Type', 'Authorization'] +})); +commentData.use(bodyParser.json()); async function Verification(req: express.Request, resp: express.Response, next: () => void) { - // req.headers.authorization のオブジェクトが未定義となるためにts-ignore - // @ts-ignore - - // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している - const tokenstr = req.headers.authorization.toString().slice(7); - - try { - const token = await admin.auth().verifyIdToken(tokenstr); - - if (token.uid == req.query['uid']) { - next(); - } else { - console.log('Error: Id token does not match \'query uid\' '); - cors(req, resp, () => { + // req.headers.authorization のオブジェクトが未定義となるためにts-ignore + // @ts-ignore + + // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している + const tokenstr = req.headers.authorization.toString().slice(7); + + try { + const token = await admin.auth().verifyIdToken(tokenstr); + + if (token.uid == req.query['uid']) { + next(); + } else { + console.log('Error: Id token does not match \'query uid\' '); + resp.status(401).send('Unauthorized'); + } + } catch (exception) { + console.log('Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again'); resp.status(401).send('Unauthorized'); - }); } - } catch (exception) { - console.log('Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again'); - await cors(); - cors(req, resp, () => { - resp.status(401).send('Unauthorized') - }); - } } -classData.use(Verification,allowCrossDomain,); -commentData.use(allowCrossDomain,Verification); + +classData.use(Verification); +commentData.use(Verification); export const WelcomeLog = functions.auth.user().onCreate((user) => { - console.log('Hello ' + user.displayName + ' logged in' + 'called by TS'); - - // データベースに書き込む。一意に定まるユーザのuidを主キーとして設定し、メアドと名前を格納する。 - ref.child('users/' + user.uid).set({ - mail: user.email, - name: user.displayName - }); - return 0; + console.log('Hello ' + user.displayName + ' logged in' + 'called by TS'); + + // データベースに書き込む。一意に定まるユーザのuidを主キーとして設定し、メアドと名前を格納する。 + ref.child('users/' + user.uid).set({ + mail: user.email, + name: user.displayName + }); + return 0; }); export const DeleteLog = functions.auth.user().onDelete((user) => { - console.log('Hello ' + user.displayName + ' account deleted ' + 'called by TS'); + console.log('Hello ' + user.displayName + ' account deleted ' + 'called by TS'); - ref.child('users/' + user.uid).remove(); + ref.child('users/' + user.uid).remove(); - return 0; + return 0; }); // build multiple CRUD interfaces: classData.get('/', async (req: functions.Request, resp: express.Response) => { - console.log('subject_query= ' + req.query['class_name']); - try { - const documentSnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); - const record = documentSnapshot.data(); - if (!record) { - console.log('class not found probably wrong or empty query'); - resp.status(404).send('Not Found'); + console.log('subject_query= ' + req.query['class_name']); + try { + const documentSnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); + const record = documentSnapshot.data(); + if (!record) { + console.log('class not found probably wrong or empty query'); + resp.status(404).send('Not Found'); + } + resp.send(JSON.stringify(record)); + } catch (exception) { + console.log('class not found probably wrong or empty query'); + resp.status(404).send('Not Found'); } - resp.send(JSON.stringify(record)); - } catch (exception) { - console.log('class not found probably wrong or empty query'); - resp.status(404).send('Not Found'); - } }); classData.post('/', async (req: functions.Request, resp: express.Response) => { - console.log('json received'); - const body = req.body; - - // Check the validity of the token - const uid = admin.auth.decodedToken(body.token).uid; - if (!uid) { - resp.status(401).send('Unauthorized'); - } else { - console.log(uid); - } - - let class_created_time = null; - const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); - if (doc.exists) { - class_created_time = doc.data().created_at; - } else { - class_created_time = moment().add(9, 'h').format(); - } - const data = { - 'name': body.name, - 'faculty': body.faculty, - 'department': body.department, - 'fav_amount': body.fav_amount, - 'grade': body.grade, - 'professor': body.professor, - 'is_random': body.is_random, - 'rating': body.rating, - 'term': body.term, - 'update_by': body.update_by, - 'created_at': class_created_time, - 'updated_at': moment().add(9, 'h').format(), - 'made_by': body.made_by - }; - try { - await fdb.collection('ClassSummary').doc(body.name).set(data); - console.log(data); - resp.status(200).send(JSON.stringify({ 'status': 'OK' })); - } catch (exception) { - console.log('An error occurred. Class data cannot add in database'); - resp.status(500).send('Internal Server Error'); - } + console.log('json received'); + const body = req.body; + + // Check the validity of the token + const uid = admin.auth.decodedToken(body.token).uid; + if (!uid) { + resp.status(401).send('Unauthorized'); + } else { + console.log(uid); + } + + let class_created_time = null; + const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); + if (doc.exists) { + class_created_time = doc.data().created_at; + } else { + class_created_time = moment().add(9, 'h').format(); + } + const data = { + 'name': body.name, + 'faculty': body.faculty, + 'department': body.department, + 'fav_amount': body.fav_amount, + 'grade': body.grade, + 'professor': body.professor, + 'is_random': body.is_random, + 'rating': body.rating, + 'term': body.term, + 'update_by': body.update_by, + 'created_at': class_created_time, + 'updated_at': moment().add(9, 'h').format(), + 'made_by': body.made_by + }; + try { + await fdb.collection('ClassSummary').doc(body.name).set(data); + console.log(data); + resp.status(200).send(JSON.stringify({'status': 'OK'})); + } catch (exception) { + console.log('An error occurred. Class data cannot add in database'); + resp.status(500).send('Internal Server Error'); + } }); // Expose Express API as a single Cloud Function: exports.class_data = functions.https.onRequest(classData); commentData.get('/', async (req: functions.Request, resp: express.Response) => { - console.log('subject_query= ' + req.query['class_name'] + ' uid=' + req.query['uid']); - try { - const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).get(); - if (!qss.data()) { - console.log('No comment were found match with ' + req.query['class_name'] + ' and this uid'); - resp.status(404).send('Not Found'); + console.log('subject_query= ' + req.query['class_name'] + ' uid=' + req.query['uid']); + try { + const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).get(); + if (!qss.data()) { + console.log('No comment were found match with ' + req.query['class_name'] + ' and this uid'); + resp.status(404).send('Not Found'); + } + resp.status(200).send(JSON.stringify(qss.data())); + } catch (exception) { + console.log('class not found probably wrong or empty query'); + resp.status(404).send('Not Found'); } - resp.status(200).send(JSON.stringify(qss.data())); - } catch (exception) { - console.log('class not found probably wrong or empty query'); - resp.status(404).send('Not Found'); - } }); commentData.post('/', async (req: functions.Request, resp: express.Response) => { - console.log('json received'); - const body = req.body; - let created_time = null; - const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); - if (doc.exists) { - created_time = doc.data().created_at; - } else { - created_time = moment().add(9, 'h').format(); - } - - const data = { - 'name': body.name, - 'title': body.title, - 'comment': body.comment, - 'created_at': created_time, - 'updated_at': moment().add(9, 'h').format(), - 'made_by': body.made_by, - 'image': body.image, - 'is_recommend': body.is_recommend - }; - // IDでなくユーザのuidを用いてデータベースに格納する - try { - await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).set(data); - console.log(data); - resp.status(200).send(JSON.stringify({ 'status': 'OK' })); - } catch (exception) { - console.log('An error occurred. Comment cannot add in database'); - resp.status(500).send('Internal Server Error'); - } + console.log('json received'); + const body = req.body; + let created_time = null; + const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); + if (doc.exists) { + created_time = doc.data().created_at; + } else { + created_time = moment().add(9, 'h').format(); + } + + const data = { + 'name': body.name, + 'title': body.title, + 'comment': body.comment, + 'created_at': created_time, + 'updated_at': moment().add(9, 'h').format(), + 'made_by': body.made_by, + 'image': body.image, + 'is_recommend': body.is_recommend + }; + // IDでなくユーザのuidを用いてデータベースに格納する + try { + await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).set(data); + console.log(data); + resp.status(200).send(JSON.stringify({'status': 'OK'})); + } catch (exception) { + console.log('An error occurred. Comment cannot add in database'); + resp.status(500).send('Internal Server Error'); + } }); commentData.delete('/', async (req: functions.Request, resp: express.Response) => { - console.log(req.query['class_name'], '+', req.query['uid']); - try { - await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).delete(); - resp.status(200); - } catch (exception) { - console.log('An error occurred. Comment cannot delete from database'); - resp.status(500).send('Internal Server Error'); - } + console.log(req.query['class_name'], '+', req.query['uid']); + try { + await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).delete(); + resp.status(200); + } catch (exception) { + console.log('An error occurred. Comment cannot delete from database'); + resp.status(500).send('Internal Server Error'); + } }); exports.comment = functions.https.onRequest(commentData); From 0cd617b00adc33634c4a1b50c8fbea413b6aaea0 Mon Sep 17 00:00:00 2001 From: kzmaro Date: Mon, 10 Feb 2020 15:43:28 +0900 Subject: [PATCH 04/31] =?UTF-8?q?updated=5Fby,made=5Fby=E3=82=92edited=5Fb?= =?UTF-8?q?y=E3=81=AB=E7=B5=B1=E4=B8=80(=E6=8E=88=E6=A5=AD,=E3=82=B3?= =?UTF-8?q?=E3=83=A1=E3=83=B3=E3=83=88=E4=B8=A1=E6=96=B9)=20swagger?= =?UTF-8?q?=E5=AE=9A=E7=BE=A9=E3=81=AEfix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/index.ts | 5 ++--- swagger.yaml | 11 ++++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/backend/functions/src/index.ts b/backend/functions/src/index.ts index 6e53076..4ee0600 100644 --- a/backend/functions/src/index.ts +++ b/backend/functions/src/index.ts @@ -119,10 +119,9 @@ classData.post('/', async (req: functions.Request, resp: express.Response) => { 'is_random': body.is_random, 'rating': body.rating, 'term': body.term, - 'update_by': body.update_by, + 'edited_by': body.edited_by, 'created_at': class_created_time, 'updated_at': moment().add(9, 'h').format(), - 'made_by': body.made_by }; try { await fdb.collection('ClassSummary').doc(body.name).set(data); @@ -168,7 +167,7 @@ commentData.post('/', async (req: functions.Request, resp: express.Response) => 'comment': body.comment, 'created_at': created_time, 'updated_at': moment().add(9, 'h').format(), - 'made_by': body.made_by, + 'edited_by': body.edited_by, 'image': body.image, 'is_recommend': body.is_recommend }; diff --git a/swagger.yaml b/swagger.yaml index a8be019..c44fd33 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -132,8 +132,7 @@ definitions: - is_random - rating - term - - update_by - - made_by + - edited_by properties: name: type: "string" @@ -154,9 +153,7 @@ definitions: example: "2.7" term: type: "string" - update_by: - type: "string" - made_by: + edited_by: type: "string" comment: type: "object" @@ -164,7 +161,7 @@ definitions: - name - title - comment - - made_by + - edited_by - image - is_recommend properties: @@ -174,7 +171,7 @@ definitions: type: "string" image: type: "string" - made_by: + edited_by: type: "string" subject: type: "string" From 875fffbe4b88d59700ef722596a04d8d1ab1db3a Mon Sep 17 00:00:00 2001 From: kzmaro Date: Mon, 10 Feb 2020 17:07:36 +0900 Subject: [PATCH 05/31] =?UTF-8?q?[WIP]=20front=E3=81=ABtoken=E3=83=88?= =?UTF-8?q?=E3=83=BC=E3=82=AF=E3=83=B3=E8=A1=A8=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 9cb52bb..6252564 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -23,6 +23,9 @@ import firebase from 'firebase'; import { Component, Vue } from 'vue-property-decorator'; import auth from './plugins/auth'; +import * as admin from '@/node_modules/firebase-admin'; +import refreshToken = admin.credential.refreshToken; +import credential from '@/node_modules/firebase-admin'; @Component export default class App extends Vue { @@ -41,12 +44,14 @@ export default class App extends Vue { // リダイレクト firebase.auth().signInWithRedirect(provider); - await firebase + const result = await firebase .auth() .getRedirectResult() .catch((e: any) => { this.errorMsg = e.toString(); }); + + console.log(result.credential.accessToken); } async logoutButtonClicked() { From dec9f2333049ab472ed681debb1fb65fa2384a5c Mon Sep 17 00:00:00 2001 From: kzmaro Date: Mon, 10 Feb 2020 17:52:40 +0900 Subject: [PATCH 06/31] =?UTF-8?q?index.ts=20=E3=83=90=E3=83=83=E3=82=AF?= =?UTF-8?q?=E3=82=A8=E3=83=B3=E3=83=89=201=E3=81=A4=E3=81=AE=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E3=82=B9=E3=82=BF=E3=83=B3=E3=82=B9=E3=81=AB=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/index.ts | 37 +++++++++++----------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/backend/functions/src/index.ts b/backend/functions/src/index.ts index 4ee0600..4d31ca3 100644 --- a/backend/functions/src/index.ts +++ b/backend/functions/src/index.ts @@ -11,23 +11,11 @@ const fdb = admin.firestore(); const ref = db.ref('server/account-data/'); -// const express = require('express'); -const cors = require('cors'); -const classData = express(); -const commentData = express(); +const app = express(); +// const commentData = express(); const moment = require('moment'); - -// Automatically allow cross-origin requests -classData.use(cors({ - allowedHeaders: ['Content-Type', 'Authorization'] -})); -classData.use(bodyParser.json()); - -commentData.use(cors({ - allowedHeaders: ['Content-Type', 'Authorization'] -})); -commentData.use(bodyParser.json()); +app.use(bodyParser.json()); async function Verification(req: express.Request, resp: express.Response, next: () => void) { // req.headers.authorization のオブジェクトが未定義となるためにts-ignore @@ -51,8 +39,7 @@ async function Verification(req: express.Request, resp: express.Response, next: } } -classData.use(Verification); -commentData.use(Verification); +app.use(Verification); export const WelcomeLog = functions.auth.user().onCreate((user) => { console.log('Hello ' + user.displayName + ' logged in' + 'called by TS'); @@ -74,7 +61,7 @@ export const DeleteLog = functions.auth.user().onDelete((user) => { }); // build multiple CRUD interfaces: -classData.get('/', async (req: functions.Request, resp: express.Response) => { +app.get('/classData', async (req: functions.Request, resp: express.Response) => { console.log('subject_query= ' + req.query['class_name']); try { const documentSnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); @@ -90,7 +77,7 @@ classData.get('/', async (req: functions.Request, resp: express.Response) => { } }); -classData.post('/', async (req: functions.Request, resp: express.Response) => { +app.post('/classData', async (req: functions.Request, resp: express.Response) => { console.log('json received'); const body = req.body; @@ -132,10 +119,8 @@ classData.post('/', async (req: functions.Request, resp: express.Response) => { resp.status(500).send('Internal Server Error'); } }); -// Expose Express API as a single Cloud Function: -exports.class_data = functions.https.onRequest(classData); -commentData.get('/', async (req: functions.Request, resp: express.Response) => { +app.get('/commentData', async (req: functions.Request, resp: express.Response) => { console.log('subject_query= ' + req.query['class_name'] + ' uid=' + req.query['uid']); try { const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).get(); @@ -150,7 +135,7 @@ commentData.get('/', async (req: functions.Request, resp: express.Response) => { } }); -commentData.post('/', async (req: functions.Request, resp: express.Response) => { +app.post('/commentData', async (req: functions.Request, resp: express.Response) => { console.log('json received'); const body = req.body; let created_time = null; @@ -183,7 +168,7 @@ commentData.post('/', async (req: functions.Request, resp: express.Response) => }); -commentData.delete('/', async (req: functions.Request, resp: express.Response) => { +app.delete('/commentData', async (req: functions.Request, resp: express.Response) => { console.log(req.query['class_name'], '+', req.query['uid']); try { await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).delete(); @@ -193,4 +178,6 @@ commentData.delete('/', async (req: functions.Request, resp: express.Response) = resp.status(500).send('Internal Server Error'); } }); -exports.comment = functions.https.onRequest(commentData); + +// Expose Express API as a single Cloud Function: +exports.app = functions.https.onRequest(app); From 76111c44c802d4a5f479e69cf11771f561e98c55 Mon Sep 17 00:00:00 2001 From: kzmaro Date: Tue, 11 Feb 2020 15:24:12 +0900 Subject: [PATCH 07/31] =?UTF-8?q?frontend=E3=80=80uid=E5=8F=96=E3=82=8A?= =?UTF-8?q?=E5=87=BA=E3=81=9D=E3=81=86=E3=81=A8=E3=81=97=E3=81=A6=E8=89=B2?= =?UTF-8?q?=E3=80=85=E8=A9=A6=E8=A1=8C=E9=8C=AF=E8=AA=A4=E3=81=97=E3=81=9F?= =?UTF-8?q?=E3=82=84=E3=81=A4=E6=B6=88=E3=81=97=E3=81=BE=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.vue | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 6252564..9cb52bb 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -23,9 +23,6 @@ import firebase from 'firebase'; import { Component, Vue } from 'vue-property-decorator'; import auth from './plugins/auth'; -import * as admin from '@/node_modules/firebase-admin'; -import refreshToken = admin.credential.refreshToken; -import credential from '@/node_modules/firebase-admin'; @Component export default class App extends Vue { @@ -44,14 +41,12 @@ export default class App extends Vue { // リダイレクト firebase.auth().signInWithRedirect(provider); - const result = await firebase + await firebase .auth() .getRedirectResult() .catch((e: any) => { this.errorMsg = e.toString(); }); - - console.log(result.credential.accessToken); } async logoutButtonClicked() { From 6ef7dc229fc20779dd930ae482f1dd07eb4c5bce Mon Sep 17 00:00:00 2001 From: kzmaro Date: Tue, 11 Feb 2020 15:30:32 +0900 Subject: [PATCH 08/31] =?UTF-8?q?=E3=82=A8=E3=83=B3=E3=83=89=E3=83=9D?= =?UTF-8?q?=E3=82=A4=E3=83=B3=E3=83=88=E7=9B=B4=E3=81=97=E3=81=A6=E3=81=AA?= =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=9F=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/index.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/functions/src/index.ts b/backend/functions/src/index.ts index 4d31ca3..7a035f2 100644 --- a/backend/functions/src/index.ts +++ b/backend/functions/src/index.ts @@ -27,7 +27,7 @@ async function Verification(req: express.Request, resp: express.Response, next: try { const token = await admin.auth().verifyIdToken(tokenstr); - if (token.uid == req.query['uid']) { + if (token.uid === req.query['uid']) { next(); } else { console.log('Error: Id token does not match \'query uid\' '); @@ -61,7 +61,7 @@ export const DeleteLog = functions.auth.user().onDelete((user) => { }); // build multiple CRUD interfaces: -app.get('/classData', async (req: functions.Request, resp: express.Response) => { +app.get('/class_data', async (req: functions.Request, resp: express.Response) => { console.log('subject_query= ' + req.query['class_name']); try { const documentSnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); @@ -77,7 +77,7 @@ app.get('/classData', async (req: functions.Request, resp: express.Response) => } }); -app.post('/classData', async (req: functions.Request, resp: express.Response) => { +app.post('/class_data', async (req: functions.Request, resp: express.Response) => { console.log('json received'); const body = req.body; @@ -120,7 +120,7 @@ app.post('/classData', async (req: functions.Request, resp: express.Response) => } }); -app.get('/commentData', async (req: functions.Request, resp: express.Response) => { +app.get('/comment', async (req: functions.Request, resp: express.Response) => { console.log('subject_query= ' + req.query['class_name'] + ' uid=' + req.query['uid']); try { const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).get(); @@ -135,7 +135,7 @@ app.get('/commentData', async (req: functions.Request, resp: express.Response) = } }); -app.post('/commentData', async (req: functions.Request, resp: express.Response) => { +app.post('/comment', async (req: functions.Request, resp: express.Response) => { console.log('json received'); const body = req.body; let created_time = null; @@ -168,7 +168,7 @@ app.post('/commentData', async (req: functions.Request, resp: express.Response) }); -app.delete('/commentData', async (req: functions.Request, resp: express.Response) => { +app.delete('/comment', async (req: functions.Request, resp: express.Response) => { console.log(req.query['class_name'], '+', req.query['uid']); try { await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).delete(); From e7c23f8c95ee8628e3adaa21355d6c71e1950870 Mon Sep 17 00:00:00 2001 From: kzmaro Date: Thu, 20 Feb 2020 18:38:36 +0900 Subject: [PATCH 09/31] =?UTF-8?q?=E4=B8=80=E9=80=9A=E3=82=8A=E3=81=AE?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=AE=8C=E4=BA=86!!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/api.ts | 178 +++++++++++++++++++++++++++++++ backend/functions/src/index.ts | 184 +-------------------------------- swagger.yaml | 4 + 3 files changed, 183 insertions(+), 183 deletions(-) create mode 100644 backend/functions/src/api.ts diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts new file mode 100644 index 0000000..da7066f --- /dev/null +++ b/backend/functions/src/api.ts @@ -0,0 +1,178 @@ +import * as functions from 'firebase-functions'; +import * as express from 'express'; + + +const admin = require('firebase-admin'); +admin.initializeApp(functions.config().firebase); + +const bodyParser = require('body-parser'); +const moment = require('moment'); +const db = admin.database(); +const fdb = admin.firestore(); +const ref = db.ref('server/account-data/'); +const app = express(); + +app.use(bodyParser.json()); + +async function Verification(req: express.Request, resp: express.Response, next: () => void) { + // req.headers.authorization のオブジェクトが未定義となるためにts-ignore + // @ts-ignore + + // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している + const tokenstr = req.headers.authorization.toString().slice(7); + + try { + const token = await admin.auth().verifyIdToken(tokenstr); + + if (token.uid === req.query['uid']) { + next(); + } else { + console.log('Error: Id token does not match \'query uid\' '); + resp.status(401).send('Unauthorized'); + } + } catch (exception) { + console.log('Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again'); + resp.status(401).send('Unauthorized'); + } +} + +app.use(Verification); + +export const WelcomeLog = functions.auth.user().onCreate((user) => { + console.log('Hello ' + user.displayName + ' logged in' + 'called by TS'); + + // データベースに書き込む。一意に定まるユーザのuidを主キーとして設定し、メアドと名前を格納する。 + ref.child('users/' + user.uid).set({ + mail: user.email, + name: user.displayName + }); + return 0; +}); + +export const DeleteLog = functions.auth.user().onDelete((user) => { + console.log('Hello ' + user.displayName + ' account deleted ' + 'called by TS'); + + ref.child('users/' + user.uid).remove(); + + return 0; +}); + +// build multiple CRUD interfaces: +app.get('/class_data', async (req: functions.Request, resp: express.Response) => { + console.log('subject_query= ' + req.query['class_name']); + try { + const documentSnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); + const record = documentSnapshot.data(); + if (!record) { + console.log('class not found probably wrong or empty query'); + resp.status(404).send('Not Found'); + } + resp.send(JSON.stringify(record)); + } catch (exception) { + console.log('class not found probably wrong or empty query'); + resp.status(404).send('Not Found'); + } +}); + +app.post('/class_data', async (req: functions.Request, resp: express.Response) => { + console.log('json received'); + const body = req.body; + + // Check the validity of the token + const uid = admin.auth.decodedToken(body.token).uid; + if (!uid) { + resp.status(401).send('Unauthorized'); + } else { + console.log(uid); + } + + let class_created_time = null; + const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); + if (doc.exists) { + class_created_time = doc.data().created_at; + } else { + class_created_time = moment().add(9, 'h').format(); + } + const data = { + 'name': body.name, + 'faculty': body.faculty, + 'department': body.department, + 'fav_amount': 0, + 'grade': body.grade, + 'professor': body.professor, + 'is_random': body.is_random, + 'rating': 0, + 'term': body.term, + 'edited_by': body.edited_by, + 'created_at': class_created_time, + 'updated_at': moment().add(9, 'h').format(), + }; + try { + await fdb.collection('ClassSummary').doc(body.name).set(data); + console.log(data); + resp.status(200).send(JSON.stringify({'status': 'OK'})); + } catch (exception) { + console.log('An error occurred. Class data cannot add in database'); + resp.status(500).send('Internal Server Error'); + } +}); + +app.get('/comment', async (req: functions.Request, resp: express.Response) => { + console.log('subject_query= ' + req.query['class_name'] + ' uid=' + req.query['uid']); + try { + const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).get(); + if (!qss.data()) { + console.log('No comment were found match with ' + req.query['class_name'] + ' and this uid'); + resp.status(404).send('Not Found'); + } + resp.status(200).send(JSON.stringify(qss.data())); + } catch (exception) { + console.log('class not found probably wrong or empty query'); + resp.status(404).send('Not Found'); + } +}); + +app.post('/comment', async (req: functions.Request, resp: express.Response) => { + console.log('json received'); + const body = req.body; + let created_time = null; + const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); + if (doc.exists) { + created_time = doc.data().created_at; + } else { + created_time = moment().add(9, 'h').format(); + } + + const data = { + // nameは授業名です。titleはコメントのタイトル ex. 神授業です!!等 + 'name': body.name, + 'title': body.title, + 'comment': body.comment, + 'created_at': created_time, + 'updated_at': moment().add(9, 'h').format(), + 'edited_by': body.edited_by, + 'image': body.image, + 'is_recommend': body.is_recommend + }; + // IDでなくユーザのuidを用いてデータベースに格納する + try { + await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).set(data); + console.log(data); + resp.status(200).send(JSON.stringify({'status': 'OK'})); + } catch (exception) { + console.log('An error occurred. Comment cannot add in database'); + resp.status(500).send('Internal Server Error'); + } +}); + + +app.delete('/comment', async (req: functions.Request, resp: express.Response) => { + console.log(req.query['class_name'], '+', req.query['uid']); + try { + await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).delete(); + resp.status(200); + } catch (exception) { + console.log('An error occurred. Comment cannot delete from database'); + resp.status(500).send('Internal Server Error'); + } +}); diff --git a/backend/functions/src/index.ts b/backend/functions/src/index.ts index 7a035f2..e1a7166 100644 --- a/backend/functions/src/index.ts +++ b/backend/functions/src/index.ts @@ -1,183 +1 @@ -import * as functions from 'firebase-functions'; -import * as express from 'express'; - -const bodyParser = require('body-parser'); - -const admin = require('firebase-admin'); -admin.initializeApp(functions.config().firebase); - -const db = admin.database(); -const fdb = admin.firestore(); - -const ref = db.ref('server/account-data/'); - -const app = express(); -// const commentData = express(); -const moment = require('moment'); - -app.use(bodyParser.json()); - -async function Verification(req: express.Request, resp: express.Response, next: () => void) { - // req.headers.authorization のオブジェクトが未定義となるためにts-ignore - // @ts-ignore - - // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している - const tokenstr = req.headers.authorization.toString().slice(7); - - try { - const token = await admin.auth().verifyIdToken(tokenstr); - - if (token.uid === req.query['uid']) { - next(); - } else { - console.log('Error: Id token does not match \'query uid\' '); - resp.status(401).send('Unauthorized'); - } - } catch (exception) { - console.log('Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again'); - resp.status(401).send('Unauthorized'); - } -} - -app.use(Verification); - -export const WelcomeLog = functions.auth.user().onCreate((user) => { - console.log('Hello ' + user.displayName + ' logged in' + 'called by TS'); - - // データベースに書き込む。一意に定まるユーザのuidを主キーとして設定し、メアドと名前を格納する。 - ref.child('users/' + user.uid).set({ - mail: user.email, - name: user.displayName - }); - return 0; -}); - -export const DeleteLog = functions.auth.user().onDelete((user) => { - console.log('Hello ' + user.displayName + ' account deleted ' + 'called by TS'); - - ref.child('users/' + user.uid).remove(); - - return 0; -}); - -// build multiple CRUD interfaces: -app.get('/class_data', async (req: functions.Request, resp: express.Response) => { - console.log('subject_query= ' + req.query['class_name']); - try { - const documentSnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); - const record = documentSnapshot.data(); - if (!record) { - console.log('class not found probably wrong or empty query'); - resp.status(404).send('Not Found'); - } - resp.send(JSON.stringify(record)); - } catch (exception) { - console.log('class not found probably wrong or empty query'); - resp.status(404).send('Not Found'); - } -}); - -app.post('/class_data', async (req: functions.Request, resp: express.Response) => { - console.log('json received'); - const body = req.body; - - // Check the validity of the token - const uid = admin.auth.decodedToken(body.token).uid; - if (!uid) { - resp.status(401).send('Unauthorized'); - } else { - console.log(uid); - } - - let class_created_time = null; - const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); - if (doc.exists) { - class_created_time = doc.data().created_at; - } else { - class_created_time = moment().add(9, 'h').format(); - } - const data = { - 'name': body.name, - 'faculty': body.faculty, - 'department': body.department, - 'fav_amount': body.fav_amount, - 'grade': body.grade, - 'professor': body.professor, - 'is_random': body.is_random, - 'rating': body.rating, - 'term': body.term, - 'edited_by': body.edited_by, - 'created_at': class_created_time, - 'updated_at': moment().add(9, 'h').format(), - }; - try { - await fdb.collection('ClassSummary').doc(body.name).set(data); - console.log(data); - resp.status(200).send(JSON.stringify({'status': 'OK'})); - } catch (exception) { - console.log('An error occurred. Class data cannot add in database'); - resp.status(500).send('Internal Server Error'); - } -}); - -app.get('/comment', async (req: functions.Request, resp: express.Response) => { - console.log('subject_query= ' + req.query['class_name'] + ' uid=' + req.query['uid']); - try { - const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).get(); - if (!qss.data()) { - console.log('No comment were found match with ' + req.query['class_name'] + ' and this uid'); - resp.status(404).send('Not Found'); - } - resp.status(200).send(JSON.stringify(qss.data())); - } catch (exception) { - console.log('class not found probably wrong or empty query'); - resp.status(404).send('Not Found'); - } -}); - -app.post('/comment', async (req: functions.Request, resp: express.Response) => { - console.log('json received'); - const body = req.body; - let created_time = null; - const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); - if (doc.exists) { - created_time = doc.data().created_at; - } else { - created_time = moment().add(9, 'h').format(); - } - - const data = { - 'name': body.name, - 'title': body.title, - 'comment': body.comment, - 'created_at': created_time, - 'updated_at': moment().add(9, 'h').format(), - 'edited_by': body.edited_by, - 'image': body.image, - 'is_recommend': body.is_recommend - }; - // IDでなくユーザのuidを用いてデータベースに格納する - try { - await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).set(data); - console.log(data); - resp.status(200).send(JSON.stringify({'status': 'OK'})); - } catch (exception) { - console.log('An error occurred. Comment cannot add in database'); - resp.status(500).send('Internal Server Error'); - } -}); - - -app.delete('/comment', async (req: functions.Request, resp: express.Response) => { - console.log(req.query['class_name'], '+', req.query['uid']); - try { - await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).delete(); - resp.status(200); - } catch (exception) { - console.log('An error occurred. Comment cannot delete from database'); - resp.status(500).send('Internal Server Error'); - } -}); - -// Expose Express API as a single Cloud Function: -exports.app = functions.https.onRequest(app); +export * from "./api" diff --git a/swagger.yaml b/swagger.yaml index c44fd33..6c3ae5e 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -167,8 +167,12 @@ definitions: properties: name: type: "string" + example: + "dummy class1" title: type: "string" + example: + "You should take this class!!" image: type: "string" edited_by: From 2a409c26289706d8293ec2ead34fe35cfc7757c1 Mon Sep 17 00:00:00 2001 From: kzmaro Date: Fri, 21 Feb 2020 16:44:44 +0900 Subject: [PATCH 10/31] =?UTF-8?q?[WIP]=20try=E3=81=A8catch=E3=81=AE?= =?UTF-8?q?=E3=83=8D=E3=82=B9=E3=83=88=E9=99=A4=E5=8E=BB=E3=81=AA=E3=81=A9?= =?UTF-8?q?=E3=81=AE=E3=82=B3=E3=83=BC=E3=83=89=E3=83=AC=E3=83=93=E3=83=A5?= =?UTF-8?q?=E3=83=BC=E7=AE=87=E6=89=80=E3=81=AE=E4=BF=AE=E6=AD=A3=E3=80=82?= =?UTF-8?q?uid=E3=82=92=E3=83=90=E3=83=83=E3=82=AF=E3=82=A8=E3=83=B3?= =?UTF-8?q?=E3=83=89=E3=81=A7=E3=82=88=E3=81=97=E3=81=AA=E3=81=AB=E3=82=84?= =?UTF-8?q?=E3=82=8B=E3=81=A8=E3=81=93=E3=82=8D=E3=81=AE=E4=BD=9C=E6=A5=AD?= =?UTF-8?q?=E4=B8=AD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/api.ts | 107 ++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 47 deletions(-) diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index da7066f..c00c2cd 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -17,13 +17,13 @@ app.use(bodyParser.json()); async function Verification(req: express.Request, resp: express.Response, next: () => void) { // req.headers.authorization のオブジェクトが未定義となるためにts-ignore // @ts-ignore - // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している const tokenstr = req.headers.authorization.toString().slice(7); try { const token = await admin.auth().verifyIdToken(tokenstr); + // tokenのuidがDBにあるかどうかを判断して、あればそのuidを返すように変更する(WIP) if (token.uid === req.query['uid']) { next(); } else { @@ -38,7 +38,7 @@ async function Verification(req: express.Request, resp: express.Response, next: app.use(Verification); -export const WelcomeLog = functions.auth.user().onCreate((user) => { +export const RegisterLog = functions.auth.user().onCreate((user) => { console.log('Hello ' + user.displayName + ' logged in' + 'called by TS'); // データベースに書き込む。一意に定まるユーザのuidを主キーとして設定し、メアドと名前を格納する。 @@ -49,7 +49,7 @@ export const WelcomeLog = functions.auth.user().onCreate((user) => { return 0; }); -export const DeleteLog = functions.auth.user().onDelete((user) => { +export const UnRegisterLog = functions.auth.user().onDelete((user) => { console.log('Hello ' + user.displayName + ' account deleted ' + 'called by TS'); ref.child('users/' + user.uid).remove(); @@ -60,20 +60,18 @@ export const DeleteLog = functions.auth.user().onDelete((user) => { // build multiple CRUD interfaces: app.get('/class_data', async (req: functions.Request, resp: express.Response) => { console.log('subject_query= ' + req.query['class_name']); - try { - const documentSnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); - const record = documentSnapshot.data(); - if (!record) { - console.log('class not found probably wrong or empty query'); - resp.status(404).send('Not Found'); - } - resp.send(JSON.stringify(record)); - } catch (exception) { + let err = ""; + const db_data = await fdb.collection('ClassSummary').doc(req.query['class_name']).get().catch((e: string) => err = e); + const record = db_data.data().catch((e: string) => err = e); + if (err !== "") { console.log('class not found probably wrong or empty query'); resp.status(404).send('Not Found'); + } else { + resp.send(JSON.stringify(record)); } }); + app.post('/class_data', async (req: functions.Request, resp: express.Response) => { console.log('json received'); const body = req.body; @@ -82,17 +80,14 @@ app.post('/class_data', async (req: functions.Request, resp: express.Response) = const uid = admin.auth.decodedToken(body.token).uid; if (!uid) { resp.status(401).send('Unauthorized'); + return 0; } else { console.log(uid); } - let class_created_time = null; const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); - if (doc.exists) { - class_created_time = doc.data().created_at; - } else { - class_created_time = moment().add(9, 'h').format(); - } + const class_created_time = doc.data().created_at || moment().add(9, 'h').format(); + const data = { 'name': body.name, 'faculty': body.faculty, @@ -107,42 +102,48 @@ app.post('/class_data', async (req: functions.Request, resp: express.Response) = 'created_at': class_created_time, 'updated_at': moment().add(9, 'h').format(), }; - try { - await fdb.collection('ClassSummary').doc(body.name).set(data); + let err = ""; + await fdb.collection('ClassSummary').doc(body.name).set(data).catch((e: string) => err = e); + + if (err !== "") { + console.log('An error occurred. Class data cannot add in database' + err); + resp.status(500).send('Internal Server Error'); + return 0; + } else { console.log(data); resp.status(200).send(JSON.stringify({'status': 'OK'})); - } catch (exception) { - console.log('An error occurred. Class data cannot add in database'); - resp.status(500).send('Internal Server Error'); + return 0; } }); app.get('/comment', async (req: functions.Request, resp: express.Response) => { console.log('subject_query= ' + req.query['class_name'] + ' uid=' + req.query['uid']); - try { - const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).get(); - if (!qss.data()) { - console.log('No comment were found match with ' + req.query['class_name'] + ' and this uid'); - resp.status(404).send('Not Found'); - } - resp.status(200).send(JSON.stringify(qss.data())); - } catch (exception) { + let err = ""; + const qss = await fdb.collection('ClassSummary') + .doc(req.query['class_name']) + .collection('comment') + .doc(req.query['uid']).get().catch((e: string) => err = e); + + if (err !== "") { console.log('class not found probably wrong or empty query'); resp.status(404).send('Not Found'); + return 0; + } else if (!qss.data()) { + console.log('No comment were found match with ' + req.query['class_name'] + ' and this uid'); + resp.status(404).send('Not Found'); + return 0; + + } else { + resp.status(200).send(JSON.stringify(qss.data())); + return 0; } }); app.post('/comment', async (req: functions.Request, resp: express.Response) => { console.log('json received'); const body = req.body; - let created_time = null; const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); - if (doc.exists) { - created_time = doc.data().created_at; - } else { - created_time = moment().add(9, 'h').format(); - } - + const created_time = doc.data().created_at || moment().add(9, 'h').format(); const data = { // nameは授業名です。titleはコメントのタイトル ex. 神授業です!!等 'name': body.name, @@ -155,24 +156,36 @@ app.post('/comment', async (req: functions.Request, resp: express.Response) => { 'is_recommend': body.is_recommend }; // IDでなくユーザのuidを用いてデータベースに格納する - try { - await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).set(data); - console.log(data); - resp.status(200).send(JSON.stringify({'status': 'OK'})); - } catch (exception) { + let err = ""; + await fdb.collection('ClassSummary') + .doc(body.name).collection('comment') + .doc(body.made_by).set(data).data().catch((e: string) => err = e); + + if (err !== "") { console.log('An error occurred. Comment cannot add in database'); resp.status(500).send('Internal Server Error'); + + } else { + console.log(data); + resp.status(200).send(JSON.stringify({'status': 'OK'})); } }); app.delete('/comment', async (req: functions.Request, resp: express.Response) => { console.log(req.query['class_name'], '+', req.query['uid']); - try { - await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).delete(); - resp.status(200); - } catch (exception) { + let err = ""; + await fdb.collection('ClassSummary') + .doc(req.query['class_name']) + .collection('comment') + .doc(req.query['uid']).delete().catch((e: string) => err = e); + + if (err !== "") { console.log('An error occurred. Comment cannot delete from database'); resp.status(500).send('Internal Server Error'); + } else { + resp.status(200); } }); + +exports.api = functions.https.onRequest(app); From 82aa73eec7b9c8da0a4d347d855d8b3d9fb61fb4 Mon Sep 17 00:00:00 2001 From: kzmaro Date: Mon, 24 Feb 2020 01:05:02 +0900 Subject: [PATCH 11/31] =?UTF-8?q?[WIP]=20=E3=82=B3=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=83=AA=E3=83=95=E3=82=A1=E3=82=AF=E3=82=BF=E3=83=AA=E3=83=B3?= =?UTF-8?q?=E3=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/api.ts | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index c00c2cd..7f8d67e 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -19,21 +19,18 @@ async function Verification(req: express.Request, resp: express.Response, next: // @ts-ignore // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している const tokenstr = req.headers.authorization.toString().slice(7); - - try { - const token = await admin.auth().verifyIdToken(tokenstr); - - // tokenのuidがDBにあるかどうかを判断して、あればそのuidを返すように変更する(WIP) - if (token.uid === req.query['uid']) { + console.log(tokenstr); + const token = await admin.auth().verifyIdToken(tokenstr); + const uid=token.uid; + console.log(uid); + ref.child('users/' + uid).once("value", (snapshot: { exists: () => any; }) => { + if (snapshot.exists()) { next(); } else { console.log('Error: Id token does not match \'query uid\' '); resp.status(401).send('Unauthorized'); } - } catch (exception) { - console.log('Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again'); - resp.status(401).send('Unauthorized'); - } + }); } app.use(Verification); @@ -60,9 +57,9 @@ export const UnRegisterLog = functions.auth.user().onDelete((user) => { // build multiple CRUD interfaces: app.get('/class_data', async (req: functions.Request, resp: express.Response) => { console.log('subject_query= ' + req.query['class_name']); - let err = ""; - const db_data = await fdb.collection('ClassSummary').doc(req.query['class_name']).get().catch((e: string) => err = e); - const record = db_data.data().catch((e: string) => err = e); + const err = ""; + const db_data = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); + const record = db_data.data(); if (err !== "") { console.log('class not found probably wrong or empty query'); resp.status(404).send('Not Found'); @@ -77,6 +74,7 @@ app.post('/class_data', async (req: functions.Request, resp: express.Response) = const body = req.body; // Check the validity of the token + const uid = admin.auth.decodedToken(body.token).uid; if (!uid) { resp.status(401).send('Unauthorized'); From cbd51edcd8ec491600cde7b5f61cfc974e7c9d67 Mon Sep 17 00:00:00 2001 From: kzmaro Date: Tue, 25 Feb 2020 16:47:23 +0900 Subject: [PATCH 12/31] =?UTF-8?q?[WIP]=20GET=20class=5Fdata=E3=81=AE?= =?UTF-8?q?=E5=AE=9F=E8=A3=85=E5=AE=8C=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/api.ts | 143 +++++++++++++++-------------------- 1 file changed, 61 insertions(+), 82 deletions(-) diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index 7f8d67e..161a8f0 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -17,20 +17,25 @@ app.use(bodyParser.json()); async function Verification(req: express.Request, resp: express.Response, next: () => void) { // req.headers.authorization のオブジェクトが未定義となるためにts-ignore // @ts-ignore + // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している const tokenstr = req.headers.authorization.toString().slice(7); - console.log(tokenstr); - const token = await admin.auth().verifyIdToken(tokenstr); - const uid=token.uid; - console.log(uid); - ref.child('users/' + uid).once("value", (snapshot: { exists: () => any; }) => { - if (snapshot.exists()) { - next(); - } else { - console.log('Error: Id token does not match \'query uid\' '); - resp.status(401).send('Unauthorized'); - } - }); + + try { + const token = await admin.auth().verifyIdToken(tokenstr); + // 送られてきたtokenを元にユーザを認証する。 + ref.child('users/' + token.uid).once("value", (snapshot: { exists: () => any; }) => { + if (snapshot.exists()) { + next(); + } else { + console.log('Error: Id token does not match \'query uid\' '); + resp.status(401).send('Unauthorized'); + } + }); + } catch (exception) { + console.log('Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again'); + resp.status(401).send('Unauthorized'); + } } app.use(Verification); @@ -43,46 +48,40 @@ export const RegisterLog = functions.auth.user().onCreate((user) => { mail: user.email, name: user.displayName }); - return 0; + return ; }); export const UnRegisterLog = functions.auth.user().onDelete((user) => { console.log('Hello ' + user.displayName + ' account deleted ' + 'called by TS'); - ref.child('users/' + user.uid).remove(); - - return 0; + return ; }); -// build multiple CRUD interfaces: + app.get('/class_data', async (req: functions.Request, resp: express.Response) => { console.log('subject_query= ' + req.query['class_name']); - const err = ""; - const db_data = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); - const record = db_data.data(); - if (err !== "") { + try { + // queryでクラス名が指定されなかった場合は全ての授業データを取得する + if (!req.query['class_name']){ + const querySnapshot = await fdb.collection('ClassSummary').get(); + const records = querySnapshot.docs.map((elem: { data: () => any; }) => elem.data()); + console.log(records); + resp.send(JSON.stringify(records)); + + } else { + const documentSnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); + const record = documentSnapshot.data(); + resp.send(JSON.stringify(record)); + } + } catch (exception) { console.log('class not found probably wrong or empty query'); resp.status(404).send('Not Found'); - } else { - resp.send(JSON.stringify(record)); } }); - app.post('/class_data', async (req: functions.Request, resp: express.Response) => { console.log('json received'); const body = req.body; - - // Check the validity of the token - - const uid = admin.auth.decodedToken(body.token).uid; - if (!uid) { - resp.status(401).send('Unauthorized'); - return 0; - } else { - console.log(uid); - } - const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); const class_created_time = doc.data().created_at || moment().add(9, 'h').format(); @@ -100,48 +99,38 @@ app.post('/class_data', async (req: functions.Request, resp: express.Response) = 'created_at': class_created_time, 'updated_at': moment().add(9, 'h').format(), }; - let err = ""; - await fdb.collection('ClassSummary').doc(body.name).set(data).catch((e: string) => err = e); - - if (err !== "") { - console.log('An error occurred. Class data cannot add in database' + err); - resp.status(500).send('Internal Server Error'); - return 0; - } else { + try { + await fdb.collection('ClassSummary').doc(body.name).set(data); console.log(data); resp.status(200).send(JSON.stringify({'status': 'OK'})); - return 0; + } catch (exception) { + console.log('An error occurred. Class data cannot add in database'); + resp.status(500).send('Internal Server Error'); } }); app.get('/comment', async (req: functions.Request, resp: express.Response) => { - console.log('subject_query= ' + req.query['class_name'] + ' uid=' + req.query['uid']); - let err = ""; - const qss = await fdb.collection('ClassSummary') - .doc(req.query['class_name']) - .collection('comment') - .doc(req.query['uid']).get().catch((e: string) => err = e); - - if (err !== "") { + console.log('subject_query= ' + req.query['class_name']); + try { + const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).get(); + if (!qss.data()) { + console.log('No comment were found match with ' + req.query['class_name'] + ' and this uid'); + resp.status(404).send('Not Found'); + return ; + } + resp.status(200).send(JSON.stringify(qss.data())); + } catch (exception) { console.log('class not found probably wrong or empty query'); resp.status(404).send('Not Found'); - return 0; - } else if (!qss.data()) { - console.log('No comment were found match with ' + req.query['class_name'] + ' and this uid'); - resp.status(404).send('Not Found'); - return 0; - - } else { - resp.status(200).send(JSON.stringify(qss.data())); - return 0; } }); app.post('/comment', async (req: functions.Request, resp: express.Response) => { console.log('json received'); const body = req.body; - const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); + const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.edited_by).get(); const created_time = doc.data().created_at || moment().add(9, 'h').format(); + const data = { // nameは授業名です。titleはコメントのタイトル ex. 神授業です!!等 'name': body.name, @@ -154,35 +143,25 @@ app.post('/comment', async (req: functions.Request, resp: express.Response) => { 'is_recommend': body.is_recommend }; // IDでなくユーザのuidを用いてデータベースに格納する - let err = ""; - await fdb.collection('ClassSummary') - .doc(body.name).collection('comment') - .doc(body.made_by).set(data).data().catch((e: string) => err = e); - - if (err !== "") { - console.log('An error occurred. Comment cannot add in database'); - resp.status(500).send('Internal Server Error'); - - } else { + try { + await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.edited_by).set(data); console.log(data); resp.status(200).send(JSON.stringify({'status': 'OK'})); + } catch (exception) { + console.log('An error occurred. Comment cannot add in database'); + resp.status(500).send('Internal Server Error'); } }); app.delete('/comment', async (req: functions.Request, resp: express.Response) => { - console.log(req.query['class_name'], '+', req.query['uid']); - let err = ""; - await fdb.collection('ClassSummary') - .doc(req.query['class_name']) - .collection('comment') - .doc(req.query['uid']).delete().catch((e: string) => err = e); - - if (err !== "") { + console.log(req.query['class_name']); + try { + await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).delete(); + resp.status(200); + } catch (exception) { console.log('An error occurred. Comment cannot delete from database'); resp.status(500).send('Internal Server Error'); - } else { - resp.status(200); } }); From c505de1c2f9466c2d4903b3035059ca138467234 Mon Sep 17 00:00:00 2001 From: kzmaro Date: Fri, 28 Feb 2020 17:14:27 +0900 Subject: [PATCH 13/31] =?UTF-8?q?[WIP]=20GET,POST=20comment=20=E3=81=BE?= =?UTF-8?q?=E3=81=A7=E5=AE=8C=E4=BA=86=E3=80=82=E6=AE=8B=E3=82=8A=E3=81=AF?= =?UTF-8?q?delete=E3=81=AE=E3=81=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/api.ts | 61 +++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index 161a8f0..ca7e407 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -12,6 +12,7 @@ const fdb = admin.firestore(); const ref = db.ref('server/account-data/'); const app = express(); +app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json()); async function Verification(req: express.Request, resp: express.Response, next: () => void) { @@ -48,13 +49,13 @@ export const RegisterLog = functions.auth.user().onCreate((user) => { mail: user.email, name: user.displayName }); - return ; + return; }); export const UnRegisterLog = functions.auth.user().onDelete((user) => { console.log('Hello ' + user.displayName + ' account deleted ' + 'called by TS'); ref.child('users/' + user.uid).remove(); - return ; + return; }); @@ -62,7 +63,7 @@ app.get('/class_data', async (req: functions.Request, resp: express.Response) => console.log('subject_query= ' + req.query['class_name']); try { // queryでクラス名が指定されなかった場合は全ての授業データを取得する - if (!req.query['class_name']){ + if (!req.query['class_name']) { const querySnapshot = await fdb.collection('ClassSummary').get(); const records = querySnapshot.docs.map((elem: { data: () => any; }) => elem.data()); console.log(records); @@ -80,10 +81,17 @@ app.get('/class_data', async (req: functions.Request, resp: express.Response) => }); app.post('/class_data', async (req: functions.Request, resp: express.Response) => { + resp.setHeader('Content-Type', 'text/plain'); console.log('json received'); + // req.setEncoding('utf8'); + console.log(req.body['name']); const body = req.body; - const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.made_by).get(); - const class_created_time = doc.data().created_at || moment().add(9, 'h').format(); + console.log(body); + + // req.headers.authorization のオブジェクトが未定義となるためにts-ignore + // @ts-ignore + const tokenstr = req.headers.authorization.toString().slice(7); + const token = await admin.auth().verifyIdToken(tokenstr); const data = { 'name': body.name, @@ -95,10 +103,11 @@ app.post('/class_data', async (req: functions.Request, resp: express.Response) = 'is_random': body.is_random, 'rating': 0, 'term': body.term, - 'edited_by': body.edited_by, - 'created_at': class_created_time, + 'edited_by': token.uid, + 'created_at': moment().add(9, 'h').format(), 'updated_at': moment().add(9, 'h').format(), }; + console.log(data); try { await fdb.collection('ClassSummary').doc(body.name).set(data); console.log(data); @@ -112,13 +121,27 @@ app.post('/class_data', async (req: functions.Request, resp: express.Response) = app.get('/comment', async (req: functions.Request, resp: express.Response) => { console.log('subject_query= ' + req.query['class_name']); try { - const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).get(); - if (!qss.data()) { - console.log('No comment were found match with ' + req.query['class_name'] + ' and this uid'); - resp.status(404).send('Not Found'); - return ; + if (req.query['comment_id']) { + // req.headers.authorization のオブジェクトが未定義となるためにts-ignore + // @ts-ignore + const tokenstr = req.headers.authorization.toString().slice(7); + const token = await admin.auth().verifyIdToken(tokenstr); + + const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(token.uid).get(); + if (!qss.data()) { + console.log('No comment were found match with ' + req.query['class_name']); + resp.status(404).send('Not Found'); + return; + } + resp.status(200).send(JSON.stringify(qss.data())); + + } else{ + + const querySnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').get(); + const records = querySnapshot.docs.map((elem: { data: () => any; }) => elem.data()); + console.log(records); + resp.send(JSON.stringify(records)); } - resp.status(200).send(JSON.stringify(qss.data())); } catch (exception) { console.log('class not found probably wrong or empty query'); resp.status(404).send('Not Found'); @@ -128,23 +151,25 @@ app.get('/comment', async (req: functions.Request, resp: express.Response) => { app.post('/comment', async (req: functions.Request, resp: express.Response) => { console.log('json received'); const body = req.body; - const doc = await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.edited_by).get(); - const created_time = doc.data().created_at || moment().add(9, 'h').format(); + // req.headers.authorization のオブジェクトが未定義となるためにts-ignore + // @ts-ignore + const tokenstr = req.headers.authorization.toString().slice(7); + const token = await admin.auth().verifyIdToken(tokenstr); const data = { // nameは授業名です。titleはコメントのタイトル ex. 神授業です!!等 'name': body.name, 'title': body.title, 'comment': body.comment, - 'created_at': created_time, + 'created_at': moment().add(9, 'h').format(), 'updated_at': moment().add(9, 'h').format(), - 'edited_by': body.edited_by, + 'edited_by': token.uid, 'image': body.image, 'is_recommend': body.is_recommend }; // IDでなくユーザのuidを用いてデータベースに格納する try { - await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(body.edited_by).set(data); + await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(token.uid).set(data); console.log(data); resp.status(200).send(JSON.stringify({'status': 'OK'})); } catch (exception) { From ba2552f21f3a6f6b17a5f1a2cfb0014672323012 Mon Sep 17 00:00:00 2001 From: kzmaro Date: Fri, 28 Feb 2020 17:32:31 +0900 Subject: [PATCH 14/31] =?UTF-8?q?api.ts:=20api=E4=BB=95=E6=A7=98=E9=80=9A?= =?UTF-8?q?=E3=82=8A=E3=81=AE=E4=BF=AE=E6=AD=A3=E5=AE=8C=E4=BA=86=20swagge?= =?UTF-8?q?r:=20subject=E3=81=A8=E3=81=8B=E3=81=84=E3=81=86=E8=AC=8E?= =?UTF-8?q?=E3=81=AE=E3=82=82=E3=81=AE=E3=81=8C=E3=81=82=E3=81=A3=E3=81=9F?= =?UTF-8?q?=E3=81=AE=E3=81=A7=E6=B6=88=E3=81=97=E3=81=9F=E3=80=82=E6=AE=8B?= =?UTF-8?q?=E4=BD=9C=E6=A5=AD:=E7=B4=B0=E3=81=8B=E3=81=84=E3=83=AA?= =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=AF=E3=82=BF=E3=83=AA=E3=83=B3=E3=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/api.ts | 8 ++++++-- swagger.yaml | 2 -- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index ca7e407..5d175cf 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -181,9 +181,13 @@ app.post('/comment', async (req: functions.Request, resp: express.Response) => { app.delete('/comment', async (req: functions.Request, resp: express.Response) => { console.log(req.query['class_name']); + // req.headers.authorization のオブジェクトが未定義となるためにts-ignore + // @ts-ignore + const tokenstr = req.headers.authorization.toString().slice(7); + const token = await admin.auth().verifyIdToken(tokenstr); try { - await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(req.query['uid']).delete(); - resp.status(200); + await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(token.uid).delete(); + resp.status(204).send({'status': 'OK'}); } catch (exception) { console.log('An error occurred. Comment cannot delete from database'); resp.status(500).send('Internal Server Error'); diff --git a/swagger.yaml b/swagger.yaml index 6c3ae5e..eeac736 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -177,8 +177,6 @@ definitions: type: "string" edited_by: type: "string" - subject: - type: "string" comment: type: "string" is_recommend: From 0e6798907c4d58038b520c63d331c5129b4615a2 Mon Sep 17 00:00:00 2001 From: kzmaro Date: Sun, 1 Mar 2020 16:07:26 +0900 Subject: [PATCH 15/31] =?UTF-8?q?=E3=83=AA=E3=83=95=E3=82=A1=E3=82=AF?= =?UTF-8?q?=E3=82=BF=E3=83=AA=E3=83=B3=E3=82=B0=E3=81=AE=E5=AE=8C=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/api.ts | 30 ++++++++++++++++++++++++------ swagger.yaml | 4 +++- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index 5d175cf..9de52d4 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -35,6 +35,7 @@ async function Verification(req: express.Request, resp: express.Response, next: }); } catch (exception) { console.log('Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again'); + console.log(exception); resp.status(401).send('Unauthorized'); } } @@ -42,7 +43,7 @@ async function Verification(req: express.Request, resp: express.Response, next: app.use(Verification); export const RegisterLog = functions.auth.user().onCreate((user) => { - console.log('Hello ' + user.displayName + ' logged in' + 'called by TS'); + console.log(`Hello ${user.displayName} logged in`); // データベースに書き込む。一意に定まるユーザのuidを主キーとして設定し、メアドと名前を格納する。 ref.child('users/' + user.uid).set({ @@ -53,14 +54,14 @@ export const RegisterLog = functions.auth.user().onCreate((user) => { }); export const UnRegisterLog = functions.auth.user().onDelete((user) => { - console.log('Hello ' + user.displayName + ' account deleted ' + 'called by TS'); + console.log(`Hello ${user.displayName} account deleted`); ref.child('users/' + user.uid).remove(); return; }); app.get('/class_data', async (req: functions.Request, resp: express.Response) => { - console.log('subject_query= ' + req.query['class_name']); + console.log(`subject_query= ${req.query['class_name']} `); try { // queryでクラス名が指定されなかった場合は全ての授業データを取得する if (!req.query['class_name']) { @@ -68,15 +69,19 @@ app.get('/class_data', async (req: functions.Request, resp: express.Response) => const records = querySnapshot.docs.map((elem: { data: () => any; }) => elem.data()); console.log(records); resp.send(JSON.stringify(records)); + return; } else { const documentSnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); const record = documentSnapshot.data(); resp.send(JSON.stringify(record)); + return; } } catch (exception) { console.log('class not found probably wrong or empty query'); + console.log(exception); resp.status(404).send('Not Found'); + return } }); @@ -112,14 +117,17 @@ app.post('/class_data', async (req: functions.Request, resp: express.Response) = await fdb.collection('ClassSummary').doc(body.name).set(data); console.log(data); resp.status(200).send(JSON.stringify({'status': 'OK'})); + return; } catch (exception) { console.log('An error occurred. Class data cannot add in database'); + console.log(exception); resp.status(500).send('Internal Server Error'); + return; } }); app.get('/comment', async (req: functions.Request, resp: express.Response) => { - console.log('subject_query= ' + req.query['class_name']); + console.log(`subject_query= ${req.query['class_name']}`); try { if (req.query['comment_id']) { // req.headers.authorization のオブジェクトが未定義となるためにts-ignore @@ -129,22 +137,26 @@ app.get('/comment', async (req: functions.Request, resp: express.Response) => { const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(token.uid).get(); if (!qss.data()) { - console.log('No comment were found match with ' + req.query['class_name']); + console.log(`No comment were found match with ${req.query['class_name']}`); resp.status(404).send('Not Found'); return; } resp.status(200).send(JSON.stringify(qss.data())); + return; - } else{ + } else { const querySnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').get(); const records = querySnapshot.docs.map((elem: { data: () => any; }) => elem.data()); console.log(records); resp.send(JSON.stringify(records)); + return; } } catch (exception) { console.log('class not found probably wrong or empty query'); + console.log(exception); resp.status(404).send('Not Found'); + return; } }); @@ -172,9 +184,12 @@ app.post('/comment', async (req: functions.Request, resp: express.Response) => { await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(token.uid).set(data); console.log(data); resp.status(200).send(JSON.stringify({'status': 'OK'})); + return; } catch (exception) { console.log('An error occurred. Comment cannot add in database'); + console.log(exception); resp.status(500).send('Internal Server Error'); + return; } }); @@ -188,9 +203,12 @@ app.delete('/comment', async (req: functions.Request, resp: express.Response) => try { await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(token.uid).delete(); resp.status(204).send({'status': 'OK'}); + return; } catch (exception) { console.log('An error occurred. Comment cannot delete from database'); + console.log(exception); resp.status(500).send('Internal Server Error'); + return; } }); diff --git a/swagger.yaml b/swagger.yaml index eeac736..79d4305 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -11,7 +11,9 @@ schemes: paths: /comment: get: - summary: "授業のコメントをコメントidから取得する、コメントidが指定されなかった場合はその授業のコメント全て取得する。" + summary: "授業のコメントをコメントidから取得する、コメントidが指定されなかった場合はその授業のコメント全て取得する。 + commentのパラメータ comment_uidについて。 uidはバックエンドで管理するため、なんらかの値が設定されていたら自分のコメントを持ってくるように処理を書きました。 + (値がセットされていない場合は全件のコメントを返す) parameters: - name: "comment_id" in: "query" From e989147af82e349b8b164bd79b75737a84a1daef Mon Sep 17 00:00:00 2001 From: reud Date: Mon, 2 Mar 2020 23:27:11 +0900 Subject: [PATCH 16/31] =?UTF-8?q?[WIP]=20=E3=81=84=E3=82=8D=E3=81=84?= =?UTF-8?q?=E3=82=8D=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/.dockerignore | 2 + backend/.gitignore | 3 + backend/Dockerfile | 23 + backend/README.md | 10 + backend/functions/.eslintrc | 20 + backend/functions/package-lock.json | 3227 +++++++++++++++++++++++++++ backend/functions/package.json | 9 +- backend/functions/src/api.ts | 366 +-- backend/functions/src/index.ts | 2 +- 9 files changed, 3501 insertions(+), 161 deletions(-) create mode 100644 backend/.dockerignore create mode 100644 backend/Dockerfile create mode 100644 backend/functions/.eslintrc create mode 100644 backend/functions/package-lock.json diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..9526137 --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,2 @@ +./functions/node_modules +./docker-mount \ No newline at end of file diff --git a/backend/.gitignore b/backend/.gitignore index 97484f0..5c9f692 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,2 +1,5 @@ node_modules functions/node_modules +docker-mount +auths +.idea \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..e4788b8 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,23 @@ +FROM node:10-alpine + +WORKDIR /app + +COPY . . +# install Firebase CLI Tools +RUN npm install -g firebase-tools eslint +RUN mkdir -p root/.config/configstore/ +RUN cd functions && \ + npm install + +ENV TOKEN 1//0ecx-Jf_IEWh_CgYIARAAGA4SNwF-L9IrKpZNehiYrEscsbD3V0HVE28HnU_wEHGUmdZxpdyexRbPz-jKpFd_EPAVGfWvcPKf0co +COPY auths/firebase-tools.json root/.config/configstore/firebase-tools.json +COPY auths/update-notifier-firebase-tools.json root/.config/configstore/update-notifier-firebase-tools.json +COPY auths/update-notifier-npm.json root/.config/configstore/update-notifier-npm.json +# settings for runtime emulator +ENV HOST 0.0.0.0 +EXPOSE 5000 + +# settings for Firebase login +EXPOSE 9005 + +# i can deploy with firebase deploy --token $TOKEN \ No newline at end of file diff --git a/backend/README.md b/backend/README.md index e110672..3d5804f 100644 --- a/backend/README.md +++ b/backend/README.md @@ -10,3 +10,13 @@ Pj-marowd Cloud Functions # Linting 1. ` cd backend/functions ` 1. ` yarn run lint ` + + +# Use with docker +ci用のtokenを使ってデプロイします。 +1. `$ firebase login:ci --no-localhost` でtokenを取得 +あとはこれ +`$ docker run --env TOKEN= --name runner-container -p 9005:9005 pj-marowd-backend /bin/sh` + +移動して`$ firebase deploy --token $TOKEN` + diff --git a/backend/functions/.eslintrc b/backend/functions/.eslintrc new file mode 100644 index 0000000..516c05d --- /dev/null +++ b/backend/functions/.eslintrc @@ -0,0 +1,20 @@ +{ + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + "prettier/@typescript-eslint" + ], + "plugins": [ + "@typescript-eslint" + ], + "env": { "node": true, "es6": true }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "sourceType": "module", + "project": "./tsconfig.json" + }, + "rules": { + } +} \ No newline at end of file diff --git a/backend/functions/package-lock.json b/backend/functions/package-lock.json new file mode 100644 index 0000000..cc8cef1 --- /dev/null +++ b/backend/functions/package-lock.json @@ -0,0 +1,3227 @@ +{ + "name": "functions", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@firebase/app-types": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.5.2.tgz", + "integrity": "sha512-k3zRi9gXyWrymu8OL6DA1Pz7eo+sKVBopX5ouOjQwozAZ55WhelifPC99WHmLWo8sAokNM0XDyzM7loOA5yliQ==" + }, + "@firebase/auth-interop-types": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.1.3.tgz", + "integrity": "sha512-Fd0MJ8hHw/MasNTJz7vl5jnMMs71X6pY/VqN0V6lqdP5HKTuyPVnffJ1d2Vb6uCLZ1D7nXAer4YWj9cOrNLPAQ==" + }, + "@firebase/component": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.1.6.tgz", + "integrity": "sha512-dm5pVhm+sU8ag1M3hY6vleA/H7Ed8sKRxbm4TAKhtjGHDejPXxnK0meTNydJ3MwisHWlwzGuzIEhb223K7FFxA==", + "requires": { + "@firebase/util": "0.2.41", + "tslib": "1.10.0" + } + }, + "@firebase/database": { + "version": "0.5.22", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.5.22.tgz", + "integrity": "sha512-3CVsmLFscFIAFOjjVhlT6HzFOhS0TKVbjhixp64oVZMOshp9qPHtHIytf6QXRAypbtZMPFAMGnhNu0pmPW/vtg==", + "requires": { + "@firebase/auth-interop-types": "0.1.3", + "@firebase/component": "0.1.6", + "@firebase/database-types": "0.4.12", + "@firebase/logger": "0.1.36", + "@firebase/util": "0.2.41", + "faye-websocket": "0.11.3", + "tslib": "1.10.0" + } + }, + "@firebase/database-types": { + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.4.12.tgz", + "integrity": "sha512-PVCTQRG9fnN1cam3Qr91+WzsCf9tO+lmUcPEb0uvafSFVhvx2U9OZOlYDdM5hS0MMHTNXI7Ywmc33EheIlLmMw==", + "requires": { + "@firebase/app-types": "0.5.2" + } + }, + "@firebase/logger": { + "version": "0.1.36", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.36.tgz", + "integrity": "sha512-5Z0ryTtzRk7kjUb0/18r10oXYu8mSPAjgdbLowRBP6HdSJB7BDiUIRS7iATSmUBZLTArdroSiFJ29m7YDfm/cw==" + }, + "@firebase/util": { + "version": "0.2.41", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.41.tgz", + "integrity": "sha512-QRu3wjU5I0ZBWrf4wgrEBYu5K5tkHjETMDPMY8WYCeekKB13k2MuJzHBjQVuStEOU7j6ygTAA0B8vXI/6B5D0g==", + "requires": { + "tslib": "1.10.0" + } + }, + "@google-cloud/common": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-2.4.0.tgz", + "integrity": "sha512-zWFjBS35eI9leAHhjfeOYlK5Plcuj/77EzstnrJIZbKgF/nkqjcQuGiMCpzCwOfPyUbz8ZaEOYgbHa759AKbjg==", + "optional": true, + "requires": { + "@google-cloud/projectify": "^1.0.0", + "@google-cloud/promisify": "^1.0.0", + "arrify": "^2.0.0", + "duplexify": "^3.6.0", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^5.5.0", + "retry-request": "^4.0.0", + "teeny-request": "^6.0.0" + } + }, + "@google-cloud/firestore": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-3.5.1.tgz", + "integrity": "sha512-cTPKg0Yh2cSwde5tlGLHccCrhSpSMSBB0SwWm1bQwTyp4I7T8USp/mEyppd6zP2u8oQaHSPcP+lHdg/aHmL4tA==", + "optional": true, + "requires": { + "deep-equal": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "google-gax": "^1.13.0", + "readable-stream": "^3.4.0", + "through2": "^3.0.0" + } + }, + "@google-cloud/paginator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-2.0.3.tgz", + "integrity": "sha512-kp/pkb2p/p0d8/SKUu4mOq8+HGwF8NPzHWkj+VKrIPQPyMRw8deZtrO/OcSiy9C/7bpfU5Txah5ltUNfPkgEXg==", + "optional": true, + "requires": { + "arrify": "^2.0.0", + "extend": "^3.0.2" + } + }, + "@google-cloud/projectify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-1.0.4.tgz", + "integrity": "sha512-ZdzQUN02eRsmTKfBj9FDL0KNDIFNjBn/d6tHQmA/+FImH5DO6ZV8E7FzxMgAUiVAUq41RFAkb25p1oHOZ8psfg==", + "optional": true + }, + "@google-cloud/promisify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-1.0.4.tgz", + "integrity": "sha512-VccZDcOql77obTnFh0TbNED/6ZbbmHDf8UMNnzO1d5g9V0Htfm4k5cllY8P1tJsRKC3zWYGRLaViiupcgVjBoQ==", + "optional": true + }, + "@google-cloud/storage": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-4.3.1.tgz", + "integrity": "sha512-/i7tAcUZDQNDs8/+oN+U2mOXdWdP2eld0pFKLkpthmWmaD89JQlrgHAFL7uvlgCSbaD7YxgbSyJebgd6YBgMgQ==", + "optional": true, + "requires": { + "@google-cloud/common": "^2.1.1", + "@google-cloud/paginator": "^2.0.0", + "@google-cloud/promisify": "^1.0.0", + "arrify": "^2.0.0", + "compressible": "^2.0.12", + "concat-stream": "^2.0.0", + "date-and-time": "^0.12.0", + "duplexify": "^3.5.0", + "extend": "^3.0.2", + "gaxios": "^2.0.1", + "gcs-resumable-upload": "^2.2.4", + "hash-stream-validation": "^0.2.2", + "mime": "^2.2.0", + "mime-types": "^2.0.8", + "onetime": "^5.1.0", + "p-limit": "^2.2.0", + "pumpify": "^2.0.0", + "readable-stream": "^3.4.0", + "snakeize": "^0.1.0", + "stream-events": "^1.0.1", + "through2": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "optional": true + } + } + }, + "@grpc/grpc-js": { + "version": "0.6.18", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-0.6.18.tgz", + "integrity": "sha512-uAzv/tM8qpbf1vpx1xPMfcUMzbfdqJtdCYAqY/LsLeQQlnTb4vApylojr+wlCyr7bZeg3AFfHvtihnNOQQt/nA==", + "optional": true, + "requires": { + "semver": "^6.2.0" + } + }, + "@grpc/proto-loader": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.3.tgz", + "integrity": "sha512-8qvUtGg77G2ZT2HqdqYoM/OY97gQd/0crSG34xNmZ4ZOsv3aQT/FQV9QfZPazTGna6MIoyUd+u6AxsoZjJ/VMQ==", + "optional": true, + "requires": { + "lodash.camelcase": "^4.3.0", + "protobufjs": "^6.8.6" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", + "optional": true + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "optional": true + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "optional": true + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", + "optional": true + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "optional": true, + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", + "optional": true + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", + "optional": true + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", + "optional": true + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", + "optional": true + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", + "optional": true + }, + "@tootallnate/once": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.0.0.tgz", + "integrity": "sha512-KYyTT/T6ALPkIRd2Ge080X/BsXvy9O0hcWTtMWkPvwAwF99+vn6Dv4GzrFT/Nn1LePr+FFDbRXXlqmsy9lw2zA==", + "optional": true + }, + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/connect": { + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", + "requires": { + "@types/node": "*" + } + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "@types/express": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.2.tgz", + "integrity": "sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.2.tgz", + "integrity": "sha512-El9yMpctM6tORDAiBwZVLMcxoTMcqqRO9dVyYcn7ycLWbvR8klrDn8CAOwRfZujZtWD7yS/mshTdz43jMOejbg==", + "requires": { + "@types/node": "*", + "@types/range-parser": "*" + } + }, + "@types/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-UoOfVEzAUpeSPmjm7h1uk5MH6KZma2z2O7a75onTGjnNvAvMVrPzPL/vBbT65iIGHWj6rokwfmYcmxmlSf2uwg==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", + "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==", + "dev": true + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==", + "optional": true + }, + "@types/mime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", + "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==" + }, + "@types/node": { + "version": "8.10.59", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.59.tgz", + "integrity": "sha512-8RkBivJrDCyPpBXhVZcjh7cQxVBSmRk9QM7hOketZzp6Tg79c0N8kkpAIito9bnJ3HCVCHVYz+KHTEbfQNfeVQ==" + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" + }, + "@types/serve-static": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", + "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/mime": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.21.0.tgz", + "integrity": "sha512-b5jjjDMxzcjh/Sbjuo7WyhrQmVJg0WipTHQgXh5Xwx10uYm6nPWqN1WGOsaNq4HR3Zh4wUx4IRQdDkCHwyewyw==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "2.21.0", + "eslint-utils": "^1.4.3", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + }, + "dependencies": { + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.21.0.tgz", + "integrity": "sha512-olKw9JP/XUkav4lq0I7S1mhGgONJF9rHNhKFn9wJlpfRVjNo3PPjSvybxEldvCXnvD+WAshSzqH5cEjPp9CsBA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.21.0", + "eslint-scope": "^5.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.21.0.tgz", + "integrity": "sha512-VrmbdrrrvvI6cPPOG7uOgGUFXNYTiSbnRq8ZMyuGa4+qmXJXVLEEz78hKuqupvkpwJQNk1Ucz1TenrRP90gmBg==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.21.0", + "@typescript-eslint/typescript-estree": "2.21.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.21.0.tgz", + "integrity": "sha512-NC/nogZNb9IK2MEFQqyDBAciOT8Lp8O3KgAfvHx2Skx6WBo+KmDqlU3R9KxHONaijfTIKtojRe3SZQyMjr3wBw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^6.3.0", + "tsutils": "^3.17.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + } + } + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "optional": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", + "dev": true + }, + "acorn-jsx": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", + "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "dev": true + }, + "agent-base": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", + "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", + "optional": true, + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, + "ajv": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + }, + "dependencies": { + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "optional": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "optional": true + }, + "bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "optional": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "optional": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "optional": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "optional": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "optional": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "optional": true + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "optional": true + }, + "date-and-time": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-0.12.0.tgz", + "integrity": "sha512-n2RJIAp93AucgF/U/Rz5WRS2Hjg5Z+QxscaaMCi6pVZT1JpJKRH+C08vyH/lRR1kxNXnPxgo3lWfd+jCb/UcuQ==", + "optional": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.1.tgz", + "integrity": "sha512-7Et6r6XfNW61CPPCIYfm1YPGSmh6+CliYeL4km7GWJcpX5LTAflGF8drLLR+MZX+2P3NZfAfSduutBbSWqER4g==", + "optional": true, + "requires": { + "es-abstract": "^1.16.3", + "es-get-iterator": "^1.0.1", + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "isarray": "^2.0.5", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0", + "side-channel": "^1.0.1", + "which-boxed-primitive": "^1.0.1", + "which-collection": "^1.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "optional": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "dicer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz", + "integrity": "sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==", + "requires": { + "streamsearch": "0.1.2" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dot-prop": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "optional": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "optional": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "optional": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "optional": true, + "requires": { + "once": "^1.4.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "optional": true + }, + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "optional": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-get-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz", + "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==", + "optional": true, + "requires": { + "es-abstract": "^1.17.4", + "has-symbols": "^1.0.1", + "is-arguments": "^1.0.4", + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "optional": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + } + } + }, + "eslint-config-prettier": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.10.0.tgz", + "integrity": "sha512-AtndijGte1rPILInUdHjvKEGbIV06NuvPrqlIEaEaWtbtvJh464mDeyGMdZEQMsGvC0ZVkiex1fSNcC4HAbRGg==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + } + }, + "eslint-plugin-prettier": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz", + "integrity": "sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "dev": true, + "requires": { + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.1.0.tgz", + "integrity": "sha512-MxYW9xKmROWF672KqjO75sszsA8Mxhw06YFeS5VHlB98KDHbOSurm3ArsjO60Eaf3QmGMCP1yn+0JQkNLo/97Q==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "optional": true + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "optional": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fast-text-encoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", + "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==", + "optional": true + }, + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "firebase-admin": { + "version": "8.9.2", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-8.9.2.tgz", + "integrity": "sha512-ix4qcx+hHnr3mnc41Z8EzQa9Mr+2nhogLEv6ktkOCCpdKJ+9HxW9vikRCElSbC8ICHLD0KIH0GVOIZK80vbvqw==", + "requires": { + "@firebase/database": "^0.5.17", + "@google-cloud/firestore": "^3.0.0", + "@google-cloud/storage": "^4.1.2", + "@types/node": "^8.10.59", + "dicer": "^0.3.0", + "jsonwebtoken": "8.1.0", + "node-forge": "0.7.4" + } + }, + "firebase-functions": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.3.0.tgz", + "integrity": "sha512-dP6PCG+OwR6RtFpOqwPsLnfiCr3CwXAm/SVGMbO53vDAk0nhUQ1WGAyHDYmIyMAkaLJkIKGwDnX7XmZ5+yAg7g==", + "requires": { + "@types/express": "^4.17.0", + "cors": "^2.8.5", + "express": "^4.17.1", + "jsonwebtoken": "^8.5.1", + "lodash": "^4.17.14" + }, + "dependencies": { + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "optional": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "gaxios": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.3.1.tgz", + "integrity": "sha512-DQOesWEx59/bm63lTX0uHDDXpGTW9oKqNsoigwCoRe2lOb5rFqxzHjLTa6aqEBecLcz69dHLw7rbS068z1fvIQ==", + "optional": true, + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-3.4.0.tgz", + "integrity": "sha512-fizmBtCXHp8b7FZuzbgKaixO8DzsSYoEVmMgZIna7x8t6cfBF3eqirODWYxVbgmasA5qudCAKiszfB7yVwroIQ==", + "optional": true, + "requires": { + "gaxios": "^2.1.0", + "json-bigint": "^0.3.0" + } + }, + "gcs-resumable-upload": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/gcs-resumable-upload/-/gcs-resumable-upload-2.3.2.tgz", + "integrity": "sha512-OPS0iAmPCV+r7PziOIhyxmQOzsazFCy76yYDOS/Z80O/7cuny1KMfqDQa2T0jLaL8EreTU7EMZG5pUuqBKgzHA==", + "optional": true, + "requires": { + "abort-controller": "^3.0.0", + "configstore": "^5.0.0", + "gaxios": "^2.0.0", + "google-auth-library": "^5.0.0", + "pumpify": "^2.0.0", + "stream-events": "^1.0.4" + } + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", + "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "google-auth-library": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.10.1.tgz", + "integrity": "sha512-rOlaok5vlpV9rSiUu5EpR0vVpc+PhN62oF4RyX/6++DG1VsaulAFEMlDYBLjJDDPI6OcNOCGAKy9UVB/3NIDXg==", + "optional": true, + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^2.1.0", + "gcp-metadata": "^3.4.0", + "gtoken": "^4.1.0", + "jws": "^4.0.0", + "lru-cache": "^5.0.0" + } + }, + "google-gax": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-1.14.2.tgz", + "integrity": "sha512-Nde+FdqALbV3QgMA4KlkxOHfrj9busnZ3EECwy/1gDJm9vhKGwDLWzErqRU5g80OoGSAMgyY7DWIfqz7ina4Jw==", + "optional": true, + "requires": { + "@grpc/grpc-js": "^0.6.18", + "@grpc/proto-loader": "^0.5.1", + "@types/fs-extra": "^8.0.1", + "@types/long": "^4.0.0", + "abort-controller": "^3.0.0", + "duplexify": "^3.6.0", + "google-auth-library": "^5.0.0", + "is-stream-ended": "^0.1.4", + "lodash.at": "^4.6.0", + "lodash.has": "^4.5.2", + "node-fetch": "^2.6.0", + "protobufjs": "^6.8.8", + "retry-request": "^4.0.0", + "semver": "^6.0.0", + "walkdir": "^0.4.0" + } + }, + "google-p12-pem": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.4.tgz", + "integrity": "sha512-S4blHBQWZRnEW44OcR7TL9WR+QCqByRvhNDZ/uuQfpxywfupikf/miba8js1jZi6ZOGv5slgSuoshCWh6EMDzg==", + "optional": true, + "requires": { + "node-forge": "^0.9.0" + }, + "dependencies": { + "node-forge": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz", + "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==", + "optional": true + } + } + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "optional": true + }, + "gtoken": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.4.tgz", + "integrity": "sha512-VxirzD0SWoFUo5p8RDP8Jt2AGyOmyYcT/pOUgDKJCK+iSw0TMqwrVfY37RXTNmoKwrzmDHSk0GMT9FsgVmnVSA==", + "optional": true, + "requires": { + "gaxios": "^2.1.0", + "google-p12-pem": "^2.0.0", + "jws": "^4.0.0", + "mime": "^2.2.0" + }, + "dependencies": { + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "optional": true + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "optional": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "optional": true + }, + "hash-stream-validation": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.2.tgz", + "integrity": "sha512-cMlva5CxWZOrlS/cY0C+9qAzesn5srhFA8IT1VPiHc9bWWBLkJfEUIZr7MWoi89oOOGmpg8ymchaOjiArsGu5A==", + "optional": true, + "requires": { + "through2": "^2.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "optional": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "optional": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-parser-js": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "optional": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "optional": true, + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "inquirer": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.5.tgz", + "integrity": "sha512-6Z5cP+LAO0rzNE7xWjWtT84jxKa5ScLEGLgegPXeO3dGeU8lNe5Ii7SlXH6KVtLGlDuaEhsvsFjrjWjw8j5lFg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "optional": true + }, + "is-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.0.tgz", + "integrity": "sha512-t5mGUXC/xRheCK431ylNiSkGGpBp8bHENBcENTkDT6ppwPzEVxNGZRvgvmOEfbWkFhA7D2GEuE2mmQTr78sl2g==", + "optional": true + }, + "is-boolean-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.0.1.tgz", + "integrity": "sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==", + "optional": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "optional": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "optional": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", + "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", + "optional": true + }, + "is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "optional": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "optional": true + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "optional": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-set": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", + "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==", + "optional": true + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "optional": true + }, + "is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", + "optional": true + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "optional": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "optional": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "optional": true + }, + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "optional": true + }, + "is-weakset": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.1.tgz", + "integrity": "sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==", + "optional": true + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "optional": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-bigint": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz", + "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=", + "optional": true, + "requires": { + "bignumber.js": "^7.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "jsonwebtoken": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.1.0.tgz", + "integrity": "sha1-xjl80uX9WD1lwAeoPce7eOaYK4M=", + "requires": { + "jws": "^3.1.4", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.0.0", + "xtend": "^4.0.1" + }, + "dependencies": { + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + } + } + }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "optional": true, + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "optional": true, + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "lodash.at": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.at/-/lodash.at-4.6.0.tgz", + "integrity": "sha1-k83OZk8KGZTqM9181A4jr9EbD/g=", + "optional": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "optional": true + }, + "lodash.has": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz", + "integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=", + "optional": true + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "optional": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "optional": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz", + "integrity": "sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w==", + "optional": true, + "requires": { + "semver": "^6.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "requires": { + "mime-db": "1.43.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", + "optional": true + }, + "node-forge": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.4.tgz", + "integrity": "sha512-8Df0906+tq/omxuCZD6PqhPaQDYuyJ1d+VITgxoIA8zvQd1ru+nMJcDChHH324MWitIgbVkAkQoGEEVJNpn/PA==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "optional": true + }, + "object-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", + "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==", + "optional": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "optional": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "optional": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "optional": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "optional": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "optional": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "protobufjs": { + "version": "6.8.8", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", + "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", + "optional": true, + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "10.17.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.17.tgz", + "integrity": "sha512-gpNnRnZP3VWzzj5k3qrpRC6Rk3H/uclhAVo1aIvwzK5p5cOrs9yEyQ8H/HBsBY0u5rrWxXEiVPQ0dEB6pkjE8Q==", + "optional": true + } + } + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "optional": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", + "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", + "optional": true, + "requires": { + "duplexify": "^4.1.1", + "inherits": "^2.0.3", + "pump": "^3.0.0" + }, + "dependencies": { + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "optional": true, + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "optional": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "optional": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "regexpp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", + "dev": true + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "retry-request": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz", + "integrity": "sha512-BINDzVtLI2BDukjWmjAIRZ0oglnCAkpP2vQjM3jdLhmT62h0xnQgciPwBRDAvHqpkPT2Wo1XuUyLyn6nbGrZQQ==", + "optional": true, + "requires": { + "debug": "^4.1.1", + "through2": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz", + "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "side-channel": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz", + "integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==", + "optional": true, + "requires": { + "es-abstract": "^1.17.0-next.1", + "object-inspect": "^1.7.0" + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "snakeize": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", + "integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=", + "optional": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "optional": true, + "requires": { + "stubs": "^3.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "optional": true + }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "optional": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "optional": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true + }, + "stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=", + "optional": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "teeny-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-6.0.2.tgz", + "integrity": "sha512-B6fxA0fSnY/bul06NggdN1nywtr5U5Uvt96pHfTi8pi4MNe6++VUWcAAFBrcMeha94s+gULwA5WvagoSZ+AcYg==", + "optional": true, + "requires": { + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.2.0", + "stream-events": "^1.0.5", + "uuid": "^3.3.2" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "optional": true, + "requires": { + "readable-stream": "2 || 3" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + }, + "tslint": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", + "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "optional": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "optional": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", + "dev": true + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "optional": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "optional": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "optional": true + }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "walkdir": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.4.1.tgz", + "integrity": "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==", + "optional": true + }, + "websocket-driver": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", + "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "requires": { + "http-parser-js": ">=0.4.0 <0.4.11", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz", + "integrity": "sha512-7BT4TwISdDGBgaemWU0N0OU7FeAEJ9Oo2P1PHRm/FCWoEi2VLWC9b6xvxAA3C/NMpxg3HXVgi0sMmGbNUbNepQ==", + "optional": true, + "requires": { + "is-bigint": "^1.0.0", + "is-boolean-object": "^1.0.0", + "is-number-object": "^1.0.3", + "is-string": "^1.0.4", + "is-symbol": "^1.0.2" + } + }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "optional": true, + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "optional": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "optional": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "optional": true + } + } +} diff --git a/backend/functions/package.json b/backend/functions/package.json index f5f23ac..4c30353 100644 --- a/backend/functions/package.json +++ b/backend/functions/package.json @@ -1,8 +1,7 @@ { "name": "functions", "scripts": { - "lint": "tslint --project tsconfig.json --fix", - "build": "tsc", + "lint": "eslint --fix src/*.ts", "serve": "npm run build && firebase serve --only functions", "shell": "npm run build && firebase functions:shell", "start": "npm run shell", @@ -22,6 +21,12 @@ "moment": "^2.24.0" }, "devDependencies": { + "@typescript-eslint/eslint-plugin": "^2.21.0", + "@typescript-eslint/parser": "^2.21.0", + "eslint": "^6.8.0", + "eslint-config-prettier": "^6.10.0", + "eslint-plugin-prettier": "^3.1.2", + "prettier": "^1.19.1", "tslint": "^5.12.0", "typescript": "^3.2.2" }, diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index 9de52d4..b7021ef 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -1,95 +1,110 @@ -import * as functions from 'firebase-functions'; -import * as express from 'express'; +import * as functions from "firebase-functions"; +import * as express from "express"; - -const admin = require('firebase-admin'); +const admin = require("firebase-admin"); admin.initializeApp(functions.config().firebase); -const bodyParser = require('body-parser'); -const moment = require('moment'); +const bodyParser = require("body-parser"); +const moment = require("moment"); const db = admin.database(); const fdb = admin.firestore(); -const ref = db.ref('server/account-data/'); +const ref = db.ref("server/account-data/"); const app = express(); -app.use(bodyParser.urlencoded({extended: true})); +app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); -async function Verification(req: express.Request, resp: express.Response, next: () => void) { - // req.headers.authorization のオブジェクトが未定義となるためにts-ignore - // @ts-ignore +async function Verification( + req: express.Request, + resp: express.Response, + next: () => void +) { + // req.headers.authorization のオブジェクトが未定義となるためにts-ignore + // @ts-ignore - // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している - const tokenstr = req.headers.authorization.toString().slice(7); + // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している + const tokenstr = req.headers.authorization.toString().slice(7); - try { - const token = await admin.auth().verifyIdToken(tokenstr); - // 送られてきたtokenを元にユーザを認証する。 - ref.child('users/' + token.uid).once("value", (snapshot: { exists: () => any; }) => { - if (snapshot.exists()) { - next(); - } else { - console.log('Error: Id token does not match \'query uid\' '); - resp.status(401).send('Unauthorized'); - } - }); - } catch (exception) { - console.log('Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again'); - console.log(exception); - resp.status(401).send('Unauthorized'); - } + try { + const token = await admin.auth().verifyIdToken(tokenstr); + // 送られてきたtokenを元にユーザを認証する。 + ref + .child("users/" + token.uid) + .once("value", (snapshot: { exists: () => any }) => { + if (snapshot.exists()) { + next(); + } else { + console.log("Error: Id token does not match 'query uid' "); + resp.status(401).send("Unauthorized"); + } + }); + } catch (exception) { + console.log( + "Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again" + ); + console.log(exception); + resp.status(401).send("Unauthorized"); + } } app.use(Verification); -export const RegisterLog = functions.auth.user().onCreate((user) => { - console.log(`Hello ${user.displayName} logged in`); +export const RegisterLog = functions.auth.user().onCreate(user => { + console.log(`Hello ${user.displayName} logged in`); - // データベースに書き込む。一意に定まるユーザのuidを主キーとして設定し、メアドと名前を格納する。 - ref.child('users/' + user.uid).set({ - mail: user.email, - name: user.displayName - }); - return; + // データベースに書き込む。一意に定まるユーザのuidを主キーとして設定し、メアドと名前を格納する。 + ref.child("users/" + user.uid).set({ + mail: user.email, + name: user.displayName + }); + return; }); -export const UnRegisterLog = functions.auth.user().onDelete((user) => { - console.log(`Hello ${user.displayName} account deleted`); - ref.child('users/' + user.uid).remove(); - return; +export const UnRegisterLog = functions.auth.user().onDelete(user => { + console.log(`Hello ${user.displayName} account deleted`); + ref.child("users/" + user.uid).remove(); + return; }); - -app.get('/class_data', async (req: functions.Request, resp: express.Response) => { - console.log(`subject_query= ${req.query['class_name']} `); +app.get( + "/class_data", + async (req: functions.Request, resp: express.Response) => { + console.log(`subject_query= ${req.query["class_name"]} `); try { - // queryでクラス名が指定されなかった場合は全ての授業データを取得する - if (!req.query['class_name']) { - const querySnapshot = await fdb.collection('ClassSummary').get(); - const records = querySnapshot.docs.map((elem: { data: () => any; }) => elem.data()); - console.log(records); - resp.send(JSON.stringify(records)); - return; - - } else { - const documentSnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).get(); - const record = documentSnapshot.data(); - resp.send(JSON.stringify(record)); - return; - } + // queryでクラス名が指定されなかった場合は全ての授業データを取得する + if (!req.query["class_name"]) { + const querySnapshot = await fdb.collection("ClassSummary").get(); + const records = querySnapshot.docs.map((elem: { data: () => any }) => + elem.data() + ); + console.log(records); + resp.send(JSON.stringify(records)); + return; + } else { + const documentSnapshot = await fdb + .collection("ClassSummary") + .doc(req.query["class_name"]) + .get(); + const record = documentSnapshot.data(); + resp.send(JSON.stringify(record)); + return; + } } catch (exception) { - console.log('class not found probably wrong or empty query'); - console.log(exception); - resp.status(404).send('Not Found'); - return + console.log("class not found probably wrong or empty query"); + console.log(exception); + resp.status(404).send("Not Found"); + return; } -}); + } +); -app.post('/class_data', async (req: functions.Request, resp: express.Response) => { - resp.setHeader('Content-Type', 'text/plain'); - console.log('json received'); +app.post( + "/class_data", + async (req: functions.Request, resp: express.Response) => { + resp.setHeader("Content-Type", "text/plain"); + console.log("json received"); // req.setEncoding('utf8'); - console.log(req.body['name']); + console.log(req.body["name"]); const body = req.body; console.log(body); @@ -99,117 +114,152 @@ app.post('/class_data', async (req: functions.Request, resp: express.Response) = const token = await admin.auth().verifyIdToken(tokenstr); const data = { - 'name': body.name, - 'faculty': body.faculty, - 'department': body.department, - 'fav_amount': 0, - 'grade': body.grade, - 'professor': body.professor, - 'is_random': body.is_random, - 'rating': 0, - 'term': body.term, - 'edited_by': token.uid, - 'created_at': moment().add(9, 'h').format(), - 'updated_at': moment().add(9, 'h').format(), + name: body.name, + faculty: body.faculty, + department: body.department, + fav_amount: 0, + grade: body.grade, + professor: body.professor, + is_random: body.is_random, + rating: 0, + term: body.term, + edited_by: token.uid, + created_at: moment() + .add(9, "h") + .format(), + updated_at: moment() + .add(9, "h") + .format() }; console.log(data); try { - await fdb.collection('ClassSummary').doc(body.name).set(data); - console.log(data); - resp.status(200).send(JSON.stringify({'status': 'OK'})); - return; + await fdb + .collection("ClassSummary") + .doc(body.name) + .set(data); + console.log(data); + resp.status(200).send(JSON.stringify({ status: "OK" })); + return; } catch (exception) { - console.log('An error occurred. Class data cannot add in database'); - console.log(exception); - resp.status(500).send('Internal Server Error'); - return; + console.log("An error occurred. Class data cannot add in database"); + console.log(exception); + resp.status(500).send("Internal Server Error"); + return; } -}); + } +); -app.get('/comment', async (req: functions.Request, resp: express.Response) => { - console.log(`subject_query= ${req.query['class_name']}`); - try { - if (req.query['comment_id']) { - // req.headers.authorization のオブジェクトが未定義となるためにts-ignore - // @ts-ignore - const tokenstr = req.headers.authorization.toString().slice(7); - const token = await admin.auth().verifyIdToken(tokenstr); - - const qss = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(token.uid).get(); - if (!qss.data()) { - console.log(`No comment were found match with ${req.query['class_name']}`); - resp.status(404).send('Not Found'); - return; - } - resp.status(200).send(JSON.stringify(qss.data())); - return; +app.get("/comment", async (req: functions.Request, resp: express.Response) => { + console.log(`subject_query= ${req.query["class_name"]}`); + try { + if (req.query["comment_id"]) { + // req.headers.authorization のオブジェクトが未定義となるためにts-ignore + // @ts-ignore + const tokenstr = req.headers.authorization.toString().slice(7); + const token = await admin.auth().verifyIdToken(tokenstr); - } else { - - const querySnapshot = await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').get(); - const records = querySnapshot.docs.map((elem: { data: () => any; }) => elem.data()); - console.log(records); - resp.send(JSON.stringify(records)); - return; - } - } catch (exception) { - console.log('class not found probably wrong or empty query'); - console.log(exception); - resp.status(404).send('Not Found'); + const qss = await fdb + .collection("ClassSummary") + .doc(req.query["class_name"]) + .collection("comment") + .doc(token.uid) + .get(); + if (!qss.data()) { + console.log( + `No comment were found match with ${req.query["class_name"]}` + ); + resp.status(404).send("Not Found"); return; + } + resp.status(200).send(JSON.stringify(qss.data())); + return; + } else { + const querySnapshot = await fdb + .collection("ClassSummary") + .doc(req.query["class_name"]) + .collection("comment") + .get(); + const records = querySnapshot.docs.map((elem: { data: () => any }) => + elem.data() + ); + console.log(records); + resp.send(JSON.stringify(records)); + return; } + } catch (exception) { + console.log("class not found probably wrong or empty query"); + console.log(exception); + resp.status(404).send("Not Found"); + return; + } }); -app.post('/comment', async (req: functions.Request, resp: express.Response) => { - console.log('json received'); - const body = req.body; +app.post("/comment", async (req: functions.Request, resp: express.Response) => { + console.log("json received"); + const body = req.body; - // req.headers.authorization のオブジェクトが未定義となるためにts-ignore - // @ts-ignore - const tokenstr = req.headers.authorization.toString().slice(7); - const token = await admin.auth().verifyIdToken(tokenstr); - const data = { - // nameは授業名です。titleはコメントのタイトル ex. 神授業です!!等 - 'name': body.name, - 'title': body.title, - 'comment': body.comment, - 'created_at': moment().add(9, 'h').format(), - 'updated_at': moment().add(9, 'h').format(), - 'edited_by': token.uid, - 'image': body.image, - 'is_recommend': body.is_recommend - }; - // IDでなくユーザのuidを用いてデータベースに格納する - try { - await fdb.collection('ClassSummary').doc(body.name).collection('comment').doc(token.uid).set(data); - console.log(data); - resp.status(200).send(JSON.stringify({'status': 'OK'})); - return; - } catch (exception) { - console.log('An error occurred. Comment cannot add in database'); - console.log(exception); - resp.status(500).send('Internal Server Error'); - return; - } + // req.headers.authorization のオブジェクトが未定義となるためにts-ignore + // @ts-ignore + const tokenstr = req.headers.authorization.toString().slice(7); + const token = await admin.auth().verifyIdToken(tokenstr); + const data = { + // nameは授業名です。titleはコメントのタイトル ex. 神授業です!!等 + name: body.name, + title: body.title, + comment: body.comment, + created_at: moment() + .add(9, "h") + .format(), + updated_at: moment() + .add(9, "h") + .format(), + edited_by: token.uid, + image: body.image, + is_recommend: body.is_recommend + }; + // IDでなくユーザのuidを用いてデータベースに格納する + try { + await fdb + .collection("ClassSummary") + .doc(body.name) + .collection("comment") + .doc(token.uid) + .set(data); + console.log(data); + resp.status(200).send(JSON.stringify({ status: "OK" })); + return; + } catch (exception) { + console.log("An error occurred. Comment cannot add in database"); + console.log(exception); + resp.status(500).send("Internal Server Error"); + return; + } }); - -app.delete('/comment', async (req: functions.Request, resp: express.Response) => { - console.log(req.query['class_name']); +app.delete( + "/comment", + async (req: functions.Request, resp: express.Response) => { + console.log(req.query["class_name"]); // req.headers.authorization のオブジェクトが未定義となるためにts-ignore // @ts-ignore const tokenstr = req.headers.authorization.toString().slice(7); const token = await admin.auth().verifyIdToken(tokenstr); try { - await fdb.collection('ClassSummary').doc(req.query['class_name']).collection('comment').doc(token.uid).delete(); - resp.status(204).send({'status': 'OK'}); - return; + await fdb + .collection("ClassSummary") + .doc(req.query["class_name"]) + .collection("comment") + .doc(token.uid) + .delete(); + resp.status(204).send({ status: "OK" }); + return; } catch (exception) { - console.log('An error occurred. Comment cannot delete from database'); - console.log(exception); - resp.status(500).send('Internal Server Error'); - return; + console.log("An error occurred. Comment cannot delete from database"); + console.log(exception); + resp.status(500).send("Internal Server Error"); + return; } -}); + } +); exports.api = functions.https.onRequest(app); diff --git a/backend/functions/src/index.ts b/backend/functions/src/index.ts index e1a7166..d158c57 100644 --- a/backend/functions/src/index.ts +++ b/backend/functions/src/index.ts @@ -1 +1 @@ -export * from "./api" +export * from "./api"; From 5ec659765d7ee810a580e2d77a59f85ac873996c Mon Sep 17 00:00:00 2001 From: reud Date: Wed, 4 Mar 2020 11:14:57 +0900 Subject: [PATCH 17/31] [WIP] --- backend/.gitignore | 3 ++- backend/Dockerfile | 13 +++++-------- backend/config.json | 3 +++ 3 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 backend/config.json diff --git a/backend/.gitignore b/backend/.gitignore index 5c9f692..ae8acdb 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -2,4 +2,5 @@ node_modules functions/node_modules docker-mount auths -.idea \ No newline at end of file +.idea +pj-marowd-key.json \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile index e4788b8..987cdf3 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -2,22 +2,19 @@ FROM node:10-alpine WORKDIR /app -COPY . . # install Firebase CLI Tools RUN npm install -g firebase-tools eslint -RUN mkdir -p root/.config/configstore/ +ADD config.json /root/.config/configstore/@google-cloud/functions-emulator/config.json +COPY . . RUN cd functions && \ npm install - -ENV TOKEN 1//0ecx-Jf_IEWh_CgYIARAAGA4SNwF-L9IrKpZNehiYrEscsbD3V0HVE28HnU_wEHGUmdZxpdyexRbPz-jKpFd_EPAVGfWvcPKf0co -COPY auths/firebase-tools.json root/.config/configstore/firebase-tools.json -COPY auths/update-notifier-firebase-tools.json root/.config/configstore/update-notifier-firebase-tools.json -COPY auths/update-notifier-npm.json root/.config/configstore/update-notifier-npm.json # settings for runtime emulator ENV HOST 0.0.0.0 +ENV GOOGLE_APPLICATION_CREDENTIALS "/app/pj-marowd-key.json" EXPOSE 5000 # settings for Firebase login EXPOSE 9005 -# i can deploy with firebase deploy --token $TOKEN \ No newline at end of file +# i can deploy with firebase deploy --token $TOKEN +# firebase serve -o 0.0.0.0 \ No newline at end of file diff --git a/backend/config.json b/backend/config.json new file mode 100644 index 0000000..24b5c2c --- /dev/null +++ b/backend/config.json @@ -0,0 +1,3 @@ +{ + "bindHost": "0.0.0.0" +} From 609879e9265037423ca38a806935dd311d7b1281 Mon Sep 17 00:00:00 2001 From: reud Date: Wed, 4 Mar 2020 12:25:46 +0900 Subject: [PATCH 18/31] =?UTF-8?q?=E5=A4=9A=E5=88=86=E3=83=87=E3=83=97?= =?UTF-8?q?=E3=83=AD=E3=82=A4=E5=87=BA=E6=9D=A5=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/README.md | 5 +- backend/functions/.eslintrc | 2 + backend/functions/src/api.ts | 64 ++++++++++--------- backend/functions/tslint.json | 115 ---------------------------------- 4 files changed, 39 insertions(+), 147 deletions(-) delete mode 100644 backend/functions/tslint.json diff --git a/backend/README.md b/backend/README.md index 3d5804f..63514a2 100644 --- a/backend/README.md +++ b/backend/README.md @@ -16,7 +16,6 @@ Pj-marowd Cloud Functions ci用のtokenを使ってデプロイします。 1. `$ firebase login:ci --no-localhost` でtokenを取得 あとはこれ -`$ docker run --env TOKEN= --name runner-container -p 9005:9005 pj-marowd-backend /bin/sh` - -移動して`$ firebase deploy --token $TOKEN` +`docker build -t runner . && docker run --env TOKEN= runner /bin/sh` +`/app`内で`$ firebase deploy --token $TOKEN` diff --git a/backend/functions/.eslintrc b/backend/functions/.eslintrc index 516c05d..d058571 100644 --- a/backend/functions/.eslintrc +++ b/backend/functions/.eslintrc @@ -16,5 +16,7 @@ "project": "./tsconfig.json" }, "rules": { + // for @kanade9 DBに渡るときスネークケースなので強制キャメルケース制約をOFFにしました。 + "@typescript-eslint/camelcase": ["error", { "properties": "never" } ] } } \ No newline at end of file diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index b7021ef..85b4ea6 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -1,11 +1,13 @@ +/* eslint-disable camelcase */ import * as functions from "firebase-functions"; import * as express from "express"; +// for @kanade9 こうすればrequireなしでかけるはず +import * as admin from "firebase-admin"; +import * as bodyParser from "body-parser"; +import * as moment from "moment"; -const admin = require("firebase-admin"); admin.initializeApp(functions.config().firebase); -const bodyParser = require("body-parser"); -const moment = require("moment"); const db = admin.database(); const fdb = admin.firestore(); const ref = db.ref("server/account-data/"); @@ -14,28 +16,33 @@ const app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); +// for @kanade9 後々トークンをもっと簡単に取ってくる方法見つけたときにこの関数を変更すれば良いだけになる様に切り出しておく +const getToken = (req: express.Request): string => { + // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している + return req.headers.authorization ? req.headers.authorization.slice(7) : ""; +}; + async function Verification( req: express.Request, resp: express.Response, next: () => void ) { - // req.headers.authorization のオブジェクトが未定義となるためにts-ignore - // @ts-ignore - - // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している - const tokenstr = req.headers.authorization.toString().slice(7); + // for @kanade9 これでreq.headers.authorizationに値が入っているかどうか見てからtokenStrに値を設定出来る + const tokenStr = getToken(req); try { - const token = await admin.auth().verifyIdToken(tokenstr); + const token = await admin.auth().verifyIdToken(tokenStr); // 送られてきたtokenを元にユーザを認証する。 ref .child("users/" + token.uid) - .once("value", (snapshot: { exists: () => any }) => { + .once("value", (snapshot: { exists: () => boolean }) => { + // for @kanade9 多分booleanが返る https://stackoverflow.com/questions/42892486/what-to-do-when-snapshot-exists-returns-false if (snapshot.exists()) { next(); } else { console.log("Error: Id token does not match 'query uid' "); - resp.status(401).send("Unauthorized"); + // for @kanade9 sendは不要のはず・・・ + resp.status(401); } }); } catch (exception) { @@ -43,17 +50,18 @@ async function Verification( "Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again" ); console.log(exception); - resp.status(401).send("Unauthorized"); + resp.status(401); } } app.use(Verification); -export const RegisterLog = functions.auth.user().onCreate(user => { +export const RegisterLog = functions.auth.user().onCreate(async user => { console.log(`Hello ${user.displayName} logged in`); // データベースに書き込む。一意に定まるユーザのuidを主キーとして設定し、メアドと名前を格納する。 - ref.child("users/" + user.uid).set({ + // for @kanade9 Promiseが返ってくるっぽいのでasync/await使ったほうがいいと思う + await ref.child("users/" + user.uid).set({ mail: user.email, name: user.displayName }); @@ -74,6 +82,7 @@ app.get( // queryでクラス名が指定されなかった場合は全ての授業データを取得する if (!req.query["class_name"]) { const querySnapshot = await fdb.collection("ClassSummary").get(); + // for @kanade9 ここany型以外に出来ない?(recordsがany[]になるの厳しい・・・) elem.data()はfirestoreにあるレコードの認識なのでinterface作って、data: () => になってほしい! const records = querySnapshot.docs.map((elem: { data: () => any }) => elem.data() ); @@ -109,9 +118,8 @@ app.post( console.log(body); // req.headers.authorization のオブジェクトが未定義となるためにts-ignore - // @ts-ignore - const tokenstr = req.headers.authorization.toString().slice(7); - const token = await admin.auth().verifyIdToken(tokenstr); + const tokenStr = getToken(req); + const token = await admin.auth().verifyIdToken(tokenStr); const data = { name: body.name, @@ -154,9 +162,8 @@ app.get("/comment", async (req: functions.Request, resp: express.Response) => { try { if (req.query["comment_id"]) { // req.headers.authorization のオブジェクトが未定義となるためにts-ignore - // @ts-ignore - const tokenstr = req.headers.authorization.toString().slice(7); - const token = await admin.auth().verifyIdToken(tokenstr); + const tokenStr = getToken(req); + const token = await admin.auth().verifyIdToken(tokenStr); const qss = await fdb .collection("ClassSummary") @@ -179,6 +186,7 @@ app.get("/comment", async (req: functions.Request, resp: express.Response) => { .doc(req.query["class_name"]) .collection("comment") .get(); + // for @kanade9 ここany型以外に出来ない?(recordsがany[]になるの厳しい・・・) elem.data()はfirestoreにあるレコードの認識なのでinterface作って、data: () => になってほしい! const records = querySnapshot.docs.map((elem: { data: () => any }) => elem.data() ); @@ -198,12 +206,11 @@ app.post("/comment", async (req: functions.Request, resp: express.Response) => { console.log("json received"); const body = req.body; - // req.headers.authorization のオブジェクトが未定義となるためにts-ignore - // @ts-ignore - const tokenstr = req.headers.authorization.toString().slice(7); - const token = await admin.auth().verifyIdToken(tokenstr); + const tokenStr = getToken(req); + const token = await admin.auth().verifyIdToken(tokenStr); const data = { - // nameは授業名です。titleはコメントのタイトル ex. 神授業です!!等 + // for @kanade9 eslintだと全角スペースを入れると怒られるのでご参考までに・・・(下の文章に含まれていたので消しました。) + // nameは授業名です。titleはコメントのタイトル ex. 神授業です!!等 name: body.name, title: body.title, comment: body.comment, @@ -240,10 +247,9 @@ app.delete( "/comment", async (req: functions.Request, resp: express.Response) => { console.log(req.query["class_name"]); - // req.headers.authorization のオブジェクトが未定義となるためにts-ignore - // @ts-ignore - const tokenstr = req.headers.authorization.toString().slice(7); - const token = await admin.auth().verifyIdToken(tokenstr); + + const tokenStr = getToken(req); + const token = await admin.auth().verifyIdToken(tokenStr); try { await fdb .collection("ClassSummary") diff --git a/backend/functions/tslint.json b/backend/functions/tslint.json deleted file mode 100644 index 98b2bfd..0000000 --- a/backend/functions/tslint.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "rules": { - // -- Strict errors -- - // These lint rules are likely always a good idea. - - // Force function overloads to be declared together. This ensures readers understand APIs. - "adjacent-overload-signatures": true, - - // Do not allow the subtle/obscure comma operator. - "ban-comma-operator": true, - - // Do not allow internal modules or namespaces . These are deprecated in favor of ES6 modules. - "no-namespace": true, - - // Do not allow parameters to be reassigned. To avoid bugs, developers should instead assign new values to new vars. - "no-parameter-reassignment": true, - - // Force the use of ES6-style imports instead of /// imports. - "no-reference": true, - - // Do not allow type assertions that do nothing. This is a big warning that the developer may not understand the - // code currently being edited (they may be incorrectly handling a different type case that does not exist). - "no-unnecessary-type-assertion": true, - - // Disallow nonsensical label usage. - "label-position": true, - - // Disallows the (often typo) syntax if (var1 = var2). Replace with if (var2) { var1 = var2 }. - "no-conditional-assignment": true, - - // Disallows constructors for primitive types (e.g. new Number('123'), though Number('123') is still allowed). - "no-construct": true, - - // Do not allow super() to be called twice in a constructor. - "no-duplicate-super": true, - - // Do not allow the same case to appear more than once in a switch block. - "no-duplicate-switch-case": true, - - // Do not allow a variable to be declared more than once in the same block. Consider function parameters in this - // rule. - "no-duplicate-variable": [true, "check-parameters"], - - // Disallows a variable definition in an inner scope from shadowing a variable in an outer scope. Developers should - // instead use a separate variable name. - "no-shadowed-variable": true, - - // Empty blocks are almost never needed. Allow the one general exception: empty catch blocks. - "no-empty": [true, "allow-empty-catch"], - - // Functions must either be handled directly (e.g. with a catch() handler) or returned to another function. - // This is a major source of errors in Cloud Functions and the team strongly recommends leaving this rule on. - "no-floating-promises": true, - - // Do not allow any imports for modules that are not in package.json. These will almost certainly fail when - // deployed. - "no-implicit-dependencies": true, - - // The 'this' keyword can only be used inside of classes. - "no-invalid-this": true, - - // Do not allow strings to be thrown because they will not include stack traces. Throw Errors instead. - "no-string-throw": true, - - // Disallow control flow statements, such as return, continue, break, and throw in finally blocks. - "no-unsafe-finally": true, - - // Expressions must always return a value. Avoids common errors like const myValue = functionReturningVoid(); - "no-void-expression": [true, "ignore-arrow-function-shorthand"], - - // Disallow duplicate imports in the same file. - "no-duplicate-imports": true, - - - // -- Strong Warnings -- - // These rules should almost never be needed, but may be included due to legacy code. - // They are left as a warning to avoid frustration with blocked deploys when the developer - // understand the warning and wants to deploy anyway. - - // Warn when an empty interface is defined. These are generally not useful. - "no-empty-interface": {"severity": "warning"}, - - // Warn when an import will have side effects. - "no-import-side-effect": {"severity": "warning"}, - - // Warn when variables are defined with var. Var has subtle meaning that can lead to bugs. Strongly prefer const for - // most values and let for values that will change. - "no-var-keyword": {"severity": "warning"}, - - // Prefer === and !== over == and !=. The latter operators support overloads that are often accidental. - "triple-equals": {"severity": "warning"}, - - // Warn when using deprecated APIs. - "deprecation": {"severity": "warning"}, - - // -- Light Warnings -- - // These rules are intended to help developers use better style. Simpler code has fewer bugs. These would be "info" - // if TSLint supported such a level. - - // prefer for( ... of ... ) to an index loop when the index is only used to fetch an object from an array. - // (Even better: check out utils like .map if transforming an array!) - "prefer-for-of": {"severity": "warning"}, - - // Warns if function overloads could be unified into a single function with optional or rest parameters. - "unified-signatures": {"severity": "warning"}, - - // Prefer const for values that will not change. This better documents code. - "prefer-const": {"severity": "warning"}, - - // Multi-line object literals and function calls should have a trailing comma. This helps avoid merge conflicts. - "trailing-comma": {"severity": "warning"} - }, - - "defaultSeverity": "error" -} From 4e741687ed9294da450411fa1720f3f8de229a27 Mon Sep 17 00:00:00 2001 From: reud Date: Wed, 4 Mar 2020 12:32:26 +0900 Subject: [PATCH 19/31] =?UTF-8?q?=E3=81=93=E3=82=8C=E3=81=A7=E3=81=93?= =?UTF-8?q?=E3=81=9D=E6=9C=AC=E5=BD=93=E3=81=AB=E3=83=87=E3=83=97=E3=83=AD?= =?UTF-8?q?=E3=82=A4=E5=87=BA=E6=9D=A5=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/functions/package.json b/backend/functions/package.json index 4c30353..c140f6c 100644 --- a/backend/functions/package.json +++ b/backend/functions/package.json @@ -4,6 +4,7 @@ "lint": "eslint --fix src/*.ts", "serve": "npm run build && firebase serve --only functions", "shell": "npm run build && firebase functions:shell", + "build": "tsc", "start": "npm run shell", "deploy": "firebase deploy --only functions", "logs": "firebase functions:log" @@ -27,7 +28,6 @@ "eslint-config-prettier": "^6.10.0", "eslint-plugin-prettier": "^3.1.2", "prettier": "^1.19.1", - "tslint": "^5.12.0", "typescript": "^3.2.2" }, "private": true From ad5b6c24feba151ebe6fa0f4d2b752e46b4a099b Mon Sep 17 00:00:00 2001 From: reud Date: Wed, 4 Mar 2020 12:50:45 +0900 Subject: [PATCH 20/31] fix README --- backend/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/README.md b/backend/README.md index 63514a2..7f8a975 100644 --- a/backend/README.md +++ b/backend/README.md @@ -17,5 +17,9 @@ ci用のtokenを使ってデプロイします。 1. `$ firebase login:ci --no-localhost` でtokenを取得 あとはこれ `docker build -t runner . && docker run --env TOKEN= runner /bin/sh` + +## deploy `/app`内で`$ firebase deploy --token $TOKEN` +## local serve +`firebase serve -o 0.0.0.0` From 12f378a59b9fe6b2142c847d9ca3767df9ba78e0 Mon Sep 17 00:00:00 2001 From: reud Date: Wed, 4 Mar 2020 17:04:31 +0900 Subject: [PATCH 21/31] =?UTF-8?q?=E8=89=B2=E3=80=85=E6=9B=B8=E3=81=84?= =?UTF-8?q?=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/.dockerignore | 5 +- backend/README.md | 21 +-- backend/functions/package.json | 2 +- backend/functions/src/api.ts | 7 +- frontend/src/App.vue | 5 + frontend/src/gen/api.ts | 234 ++++++++------------------------- frontend/src/gen/base.ts | 2 +- swagger.yaml | 7 +- 8 files changed, 84 insertions(+), 199 deletions(-) diff --git a/backend/.dockerignore b/backend/.dockerignore index 9526137..6a44304 100644 --- a/backend/.dockerignore +++ b/backend/.dockerignore @@ -1,2 +1,3 @@ -./functions/node_modules -./docker-mount \ No newline at end of file +functions/node_modules +docker-mount +functions/lib \ No newline at end of file diff --git a/backend/README.md b/backend/README.md index 7f8a975..34a84b9 100644 --- a/backend/README.md +++ b/backend/README.md @@ -11,15 +11,16 @@ Pj-marowd Cloud Functions 1. ` cd backend/functions ` 1. ` yarn run lint ` +# Dockerを使ったローカル動作確認手順 +## (一回で良い)ci用トークンの取得 +- `docker build -t runner . && docker run runner /bin/sh` でコンテナを作ってその中に入る +- コンテナ内で`firebase login:ci --no-localhost` でログインするとtokenが取得できるのでメモる。 -# Use with docker -ci用のtokenを使ってデプロイします。 -1. `$ firebase login:ci --no-localhost` でtokenを取得 -あとはこれ -`docker build -t runner . && docker run --env TOKEN= runner /bin/sh` +## ローカルにCloud Functionsを立てて動作確認(localhost:5000) +- 先ほど作成したci用トークンを取得して`docker build -t runner . && docker run --env TOKEN= runner /bin/sh` +- `cd functions` +- `npm run serve`で動作します。 -## deploy -`/app`内で`$ firebase deploy --token $TOKEN` - -## local serve -`firebase serve -o 0.0.0.0` +## デプロイ +- 先ほど作成したci用トークンを取得して`docker build -t runner . && docker run --env TOKEN= runner /bin/sh` +- `firebase deploy --token $TOKEN`で動作します。 \ No newline at end of file diff --git a/backend/functions/package.json b/backend/functions/package.json index c140f6c..23f028a 100644 --- a/backend/functions/package.json +++ b/backend/functions/package.json @@ -2,7 +2,7 @@ "name": "functions", "scripts": { "lint": "eslint --fix src/*.ts", - "serve": "npm run build && firebase serve --only functions", + "serve": "npm run build && firebase serve -o 0.0.0.0", "shell": "npm run build && firebase functions:shell", "build": "tsc", "start": "npm run shell", diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index 85b4ea6..dee8e20 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -19,7 +19,10 @@ app.use(bodyParser.json()); // for @kanade9 後々トークンをもっと簡単に取ってくる方法見つけたときにこの関数を変更すれば良いだけになる様に切り出しておく const getToken = (req: express.Request): string => { // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している - return req.headers.authorization ? req.headers.authorization.slice(7) : ""; + console.log(`METOD: ${req.method}`); + console.log(`headers: ${JSON.stringify(req.headers)}`); + console.log(JSON.stringify(req.headers.authorization)); + return req.headers.authorization ? req.headers.authorization : ""; }; async function Verification( @@ -29,7 +32,7 @@ async function Verification( ) { // for @kanade9 これでreq.headers.authorizationに値が入っているかどうか見てからtokenStrに値を設定出来る const tokenStr = getToken(req); - + console.log(`token: ${tokenStr}`); try { const token = await admin.auth().verifyIdToken(tokenStr); // 送られてきたtokenを元にユーザを認証する。 diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 9cb52bb..30754ba 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -33,6 +33,11 @@ export default class App extends Vue { async created() { // 認証状態の取得 (認証済みでない場合はfalseが入る) this.isUserLoggedIn = await auth(); + if (this.isUserLoggedIn) { + const user = (this.isUserLoggedIn as firebase.User); + console.log('will output id token'); + console.log(await user.getIdToken()); + } } async loginButtonClicked() { diff --git a/frontend/src/gen/api.ts b/frontend/src/gen/api.ts index 30e46fe..1691578 100644 --- a/frontend/src/gen/api.ts +++ b/frontend/src/gen/api.ts @@ -11,7 +11,7 @@ * Do not edit the class manually. */ -// @ts-ignore + import * as globalImportUrl from 'url'; import { Configuration } from './configuration'; import globalAxios, { AxiosPromise, AxiosInstance } from 'axios'; @@ -48,13 +48,7 @@ export interface Comment { * @type {string} * @memberof Comment */ - madeBy: string; - /** - * - * @type {string} - * @memberof Comment - */ - subject?: string; + editedBy: string; /** * * @type {string} @@ -80,12 +74,6 @@ export interface ModelClass { * @memberof ModelClass */ name: string; - /** - * - * @type {string} - * @memberof ModelClass - */ - title: string; /** * * @type {string} @@ -139,13 +127,7 @@ export interface ModelClass { * @type {string} * @memberof ModelClass */ - updateBy: string; - /** - * - * @type {string} - * @memberof ModelClass - */ - madeBy: string; + editedBy: string; } /** @@ -158,10 +140,15 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati * * @summary 授業データを取得する、授業名が指定された場合、その授業のデータを取得する。 * @param {string} [className] + * @param {string} [faculty] + * @param {string} [department] + * @param {string} [grade] + * @param {string} [professor] + * @param {string} [term] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - classDataGet(className?: string, options: any = {}): RequestArgs { + classDataGet(className?: string, faculty?: string, department?: string, grade?: string, professor?: string, term?: string, options: any = {}): RequestArgs { const localVarPath = `/class_data`; const localVarUrlObj = globalImportUrl.parse(localVarPath, true); let baseOptions; @@ -176,6 +163,26 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati localVarQueryParameter['class_name'] = className; } + if (faculty !== undefined) { + localVarQueryParameter['faculty'] = faculty; + } + + if (department !== undefined) { + localVarQueryParameter['department'] = department; + } + + if (grade !== undefined) { + localVarQueryParameter['grade'] = grade; + } + + if (professor !== undefined) { + localVarQueryParameter['professor'] = professor; + } + + if (term !== undefined) { + localVarQueryParameter['term'] = term; + } + localVarUrlObj.query = {...localVarUrlObj.query, ...localVarQueryParameter, ...options.query}; @@ -282,7 +289,7 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati }, /** * - * @summary 授業のコメントをコメントidから取得する、コメントidが指定されなかった場合はその授業のコメント全て取得する。 + * @summary 授業のコメントをコメントidから取得する、コメントidが指定されなかった場合はその授業のコメント全て取得する。 commentのパラメータ comment_uidについて。 uidはバックエンドで管理するため、なんらかの値が設定されていたら自分のコメントを持ってくるように処理を書きました。 (値がセットされていない場合は全件のコメントを返す) * @param {string} className * @param {number} [commentId] * @param {*} [options] Override http request option. @@ -373,82 +380,6 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || ""); - return { - url: globalImportUrl.format(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @summary コメントを一括取得する - * @param {string} className - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - commentsGet(className: string, options: any = {}): RequestArgs { - // verify required parameter 'className' is not null or undefined - if (className === null || className === undefined) { - throw new RequiredError('className','Required parameter className was null or undefined when calling commentsGet.'); - } - const localVarPath = `/comments`; - const localVarUrlObj = globalImportUrl.parse(localVarPath, true); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - if (className !== undefined) { - localVarQueryParameter['class_name'] = className; - } - - - - localVarUrlObj.query = {...localVarUrlObj.query, ...localVarQueryParameter, ...options.query}; - // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 - delete localVarUrlObj.search; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...options.headers}; - - return { - url: globalImportUrl.format(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @summary 授業データがすでに存在しているかを確認する - * @param {string} className - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - existClassGet(className: string, options: any = {}): RequestArgs { - // verify required parameter 'className' is not null or undefined - if (className === null || className === undefined) { - throw new RequiredError('className','Required parameter className was null or undefined when calling existClassGet.'); - } - const localVarPath = `/exist_class`; - const localVarUrlObj = globalImportUrl.parse(localVarPath, true); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - if (className !== undefined) { - localVarQueryParameter['class_name'] = className; - } - - - - localVarUrlObj.query = {...localVarUrlObj.query, ...localVarQueryParameter, ...options.query}; - // fix override query string Detail: https://stackoverflow.com/a/7517673/1077943 - delete localVarUrlObj.search; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...options.headers}; - return { url: globalImportUrl.format(localVarUrlObj), options: localVarRequestOptions, @@ -467,11 +398,16 @@ export const DefaultApiFp = function(configuration?: Configuration) { * * @summary 授業データを取得する、授業名が指定された場合、その授業のデータを取得する。 * @param {string} [className] + * @param {string} [faculty] + * @param {string} [department] + * @param {string} [grade] + * @param {string} [professor] + * @param {string} [term] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - classDataGet(className?: string, options?: any): (axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = DefaultApiAxiosParamCreator(configuration).classDataGet(className, options); + classDataGet(className?: string, faculty?: string, department?: string, grade?: string, professor?: string, term?: string, options?: any): (axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = DefaultApiAxiosParamCreator(configuration).classDataGet(className, faculty, department, grade, professor, term, options); return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { const axiosRequestArgs = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; return axios.request(axiosRequestArgs); @@ -507,7 +443,7 @@ export const DefaultApiFp = function(configuration?: Configuration) { }, /** * - * @summary 授業のコメントをコメントidから取得する、コメントidが指定されなかった場合はその授業のコメント全て取得する。 + * @summary 授業のコメントをコメントidから取得する、コメントidが指定されなかった場合はその授業のコメント全て取得する。 commentのパラメータ comment_uidについて。 uidはバックエンドで管理するため、なんらかの値が設定されていたら自分のコメントを持ってくるように処理を書きました。 (値がセットされていない場合は全件のコメントを返す) * @param {string} className * @param {number} [commentId] * @param {*} [options] Override http request option. @@ -535,34 +471,6 @@ export const DefaultApiFp = function(configuration?: Configuration) { return axios.request(axiosRequestArgs); }; }, - /** - * - * @summary コメントを一括取得する - * @param {string} className - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - commentsGet(className: string, options?: any): (axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = DefaultApiAxiosParamCreator(configuration).commentsGet(className, options); - return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { - const axiosRequestArgs = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; - return axios.request(axiosRequestArgs); - }; - }, - /** - * - * @summary 授業データがすでに存在しているかを確認する - * @param {string} className - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - existClassGet(className: string, options?: any): (axios?: AxiosInstance, basePath?: string) => AxiosPromise { - const localVarAxiosArgs = DefaultApiAxiosParamCreator(configuration).existClassGet(className, options); - return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { - const axiosRequestArgs = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; - return axios.request(axiosRequestArgs); - }; - }, } }; @@ -576,11 +484,16 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa * * @summary 授業データを取得する、授業名が指定された場合、その授業のデータを取得する。 * @param {string} [className] + * @param {string} [faculty] + * @param {string} [department] + * @param {string} [grade] + * @param {string} [professor] + * @param {string} [term] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - classDataGet(className?: string, options?: any) { - return DefaultApiFp(configuration).classDataGet(className, options)(axios, basePath); + classDataGet(className?: string, faculty?: string, department?: string, grade?: string, professor?: string, term?: string, options?: any) { + return DefaultApiFp(configuration).classDataGet(className, faculty, department, grade, professor, term, options)(axios, basePath); }, /** * @@ -604,7 +517,7 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa }, /** * - * @summary 授業のコメントをコメントidから取得する、コメントidが指定されなかった場合はその授業のコメント全て取得する。 + * @summary 授業のコメントをコメントidから取得する、コメントidが指定されなかった場合はその授業のコメント全て取得する。 commentのパラメータ comment_uidについて。 uidはバックエンドで管理するため、なんらかの値が設定されていたら自分のコメントを持ってくるように処理を書きました。 (値がセットされていない場合は全件のコメントを返す) * @param {string} className * @param {number} [commentId] * @param {*} [options] Override http request option. @@ -624,26 +537,6 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa commentPost(className: string, body: Comment, options?: any) { return DefaultApiFp(configuration).commentPost(className, body, options)(axios, basePath); }, - /** - * - * @summary コメントを一括取得する - * @param {string} className - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - commentsGet(className: string, options?: any) { - return DefaultApiFp(configuration).commentsGet(className, options)(axios, basePath); - }, - /** - * - * @summary 授業データがすでに存在しているかを確認する - * @param {string} className - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - existClassGet(className: string, options?: any) { - return DefaultApiFp(configuration).existClassGet(className, options)(axios, basePath); - }, }; }; @@ -658,12 +551,17 @@ export class DefaultApi extends BaseAPI { * * @summary 授業データを取得する、授業名が指定された場合、その授業のデータを取得する。 * @param {string} [className] + * @param {string} [faculty] + * @param {string} [department] + * @param {string} [grade] + * @param {string} [professor] + * @param {string} [term] * @param {*} [options] Override http request option. * @throws {RequiredError} * @memberof DefaultApi */ - public classDataGet(className?: string, options?: any) { - return DefaultApiFp(this.configuration).classDataGet(className, options)(this.axios, this.basePath); + public classDataGet(className?: string, faculty?: string, department?: string, grade?: string, professor?: string, term?: string, options?: any) { + return DefaultApiFp(this.configuration).classDataGet(className, faculty, department, grade, professor, term, options)(this.axios, this.basePath); } /** @@ -692,7 +590,7 @@ export class DefaultApi extends BaseAPI { /** * - * @summary 授業のコメントをコメントidから取得する、コメントidが指定されなかった場合はその授業のコメント全て取得する。 + * @summary 授業のコメントをコメントidから取得する、コメントidが指定されなかった場合はその授業のコメント全て取得する。 commentのパラメータ comment_uidについて。 uidはバックエンドで管理するため、なんらかの値が設定されていたら自分のコメントを持ってくるように処理を書きました。 (値がセットされていない場合は全件のコメントを返す) * @param {string} className * @param {number} [commentId] * @param {*} [options] Override http request option. @@ -716,30 +614,6 @@ export class DefaultApi extends BaseAPI { return DefaultApiFp(this.configuration).commentPost(className, body, options)(this.axios, this.basePath); } - /** - * - * @summary コメントを一括取得する - * @param {string} className - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof DefaultApi - */ - public commentsGet(className: string, options?: any) { - return DefaultApiFp(this.configuration).commentsGet(className, options)(this.axios, this.basePath); - } - - /** - * - * @summary 授業データがすでに存在しているかを確認する - * @param {string} className - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof DefaultApi - */ - public existClassGet(className: string, options?: any) { - return DefaultApiFp(this.configuration).existClassGet(className, options)(this.axios, this.basePath); - } - } diff --git a/frontend/src/gen/base.ts b/frontend/src/gen/base.ts index c2aeeb9..0572d02 100644 --- a/frontend/src/gen/base.ts +++ b/frontend/src/gen/base.ts @@ -17,7 +17,7 @@ import { Configuration } from "./configuration"; // @ts-ignore import globalAxios, { AxiosPromise, AxiosInstance } from 'axios'; -export const BASE_PATH = "https://us-central1-pj-marowd.cloudfunctions.net".replace(/\/+$/, ""); +export const BASE_PATH = "http://localhost:5000".replace(/\/+$/, ""); /** * diff --git a/swagger.yaml b/swagger.yaml index 79d4305..a2b8b97 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -4,16 +4,17 @@ info: version: "1.0.0" title: "フロント⇆バックエンド用リファレンス" -host: "us-central1-pj-marowd.cloudfunctions.net" +host: "localhost:5000" +basePath: "/pj-marowd/us-central1/api/" schemes: - - "https" + - "http" paths: /comment: get: summary: "授業のコメントをコメントidから取得する、コメントidが指定されなかった場合はその授業のコメント全て取得する。 commentのパラメータ comment_uidについて。 uidはバックエンドで管理するため、なんらかの値が設定されていたら自分のコメントを持ってくるように処理を書きました。 - (値がセットされていない場合は全件のコメントを返す) + (値がセットされていない場合は全件のコメントを返す)" parameters: - name: "comment_id" in: "query" From 1bf7b784af4d38f1686ae1af66d19c26f69d17ec Mon Sep 17 00:00:00 2001 From: kzmaro Date: Fri, 6 Mar 2020 21:52:18 +0900 Subject: [PATCH 22/31] =?UTF-8?q?options=E3=83=A1=E3=82=BD=E3=83=83?= =?UTF-8?q?=E3=83=89=E3=81=AE=E8=80=83=E6=85=AE=E3=81=AA=E3=81=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/api.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index dee8e20..362413c 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -56,7 +56,20 @@ async function Verification( resp.status(401); } } - +app.use(function( + req: express.Request, + resp: express.Response, + next: () => void +) { + resp.header("Access-Control-Allow-Origin", req.headers.origin); + resp.header( + "Access-Control-Allow-Headers", + "X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept" + ); + resp.header("Access-Control-Allow-Methods", "POST, GET,DELETE, OPTIONS"); + resp.header("Access-Control-Max-Age", "8640"); + next(); +}); app.use(Verification); export const RegisterLog = functions.auth.user().onCreate(async user => { @@ -77,6 +90,10 @@ export const UnRegisterLog = functions.auth.user().onDelete(user => { return; }); +app.options("*", function(req, res) { + res.sendStatus(200); +}); + app.get( "/class_data", async (req: functions.Request, resp: express.Response) => { From 6b13b89e6f938eff39094155a40aa7ae073db29e Mon Sep 17 00:00:00 2001 From: kazuya <47267817+kanade9@users.noreply.github.com> Date: Sun, 8 Mar 2020 17:06:14 +0900 Subject: [PATCH 23/31] Update swagger.yaml --- swagger.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swagger.yaml b/swagger.yaml index 79d4305..3058953 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -13,7 +13,7 @@ paths: get: summary: "授業のコメントをコメントidから取得する、コメントidが指定されなかった場合はその授業のコメント全て取得する。 commentのパラメータ comment_uidについて。 uidはバックエンドで管理するため、なんらかの値が設定されていたら自分のコメントを持ってくるように処理を書きました。 - (値がセットされていない場合は全件のコメントを返す) + (値がセットされていない場合は全件のコメントを返す)" parameters: - name: "comment_id" in: "query" From fd5ef9e53be9d89f30d1dae3d1ea313a7a61f59a Mon Sep 17 00:00:00 2001 From: reiji <31179220+reud@users.noreply.github.com> Date: Sun, 8 Mar 2020 18:04:57 +0900 Subject: [PATCH 24/31] =?UTF-8?q?=E3=81=AB=E3=82=83n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit host: "localhost:5000" basePath: "/pj-marowd/us-central1/api/" --- swagger.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/swagger.yaml b/swagger.yaml index a2b8b97..64b0ab3 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -4,9 +4,8 @@ info: version: "1.0.0" title: "フロント⇆バックエンド用リファレンス" -host: "localhost:5000" -basePath: "/pj-marowd/us-central1/api/" +host: "us-central1-pj-marowd.cloudfunctions.net" schemes: - "http" paths: From 5f505f661e09f3723cb5710ad1931b852b57ff76 Mon Sep 17 00:00:00 2001 From: reiji <31179220+reud@users.noreply.github.com> Date: Sun, 8 Mar 2020 18:05:48 +0900 Subject: [PATCH 25/31] change scheme --- swagger.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swagger.yaml b/swagger.yaml index 64b0ab3..672385b 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -7,7 +7,7 @@ info: host: "us-central1-pj-marowd.cloudfunctions.net" schemes: - - "http" + - "https" paths: /comment: get: From 494252944a0a29e409c34eafcb8febb19053f797 Mon Sep 17 00:00:00 2001 From: reud Date: Sun, 8 Mar 2020 19:43:05 +0900 Subject: [PATCH 26/31] add --- backend/functions/package-lock.json | 249 ++++++---------------------- backend/functions/package.json | 1 + backend/functions/src/api.ts | 13 ++ 3 files changed, 67 insertions(+), 196 deletions(-) diff --git a/backend/functions/package-lock.json b/backend/functions/package-lock.json index cc8cef1..6f6fc17 100644 --- a/backend/functions/package-lock.json +++ b/backend/functions/package-lock.json @@ -126,8 +126,7 @@ "@google-cloud/promisify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-1.0.4.tgz", - "integrity": "sha512-VccZDcOql77obTnFh0TbNED/6ZbbmHDf8UMNnzO1d5g9V0Htfm4k5cllY8P1tJsRKC3zWYGRLaViiupcgVjBoQ==", - "optional": true + "integrity": "sha512-VccZDcOql77obTnFh0TbNED/6ZbbmHDf8UMNnzO1d5g9V0Htfm4k5cllY8P1tJsRKC3zWYGRLaViiupcgVjBoQ==" }, "@google-cloud/storage": { "version": "4.3.1", @@ -189,32 +188,27 @@ "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", - "optional": true + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" }, "@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "optional": true + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" }, "@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "optional": true + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" }, "@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", - "optional": true + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" }, "@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "optional": true, "requires": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -223,32 +217,27 @@ "@protobufjs/float": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", - "optional": true + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" }, "@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", - "optional": true + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" }, "@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", - "optional": true + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" }, "@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", - "optional": true + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" }, "@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", - "optional": true + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" }, "@tootallnate/once": { "version": "1.0.0", @@ -279,6 +268,14 @@ "@types/node": "*" } }, + "@types/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-invOmosX0DqbpA+cE2yoHGUlF/blyf7nB0OGYBBiH27crcVm5NmFaZkLP4Ta1hGaesckCi5lVLlydNJCxkTOSg==", + "requires": { + "@types/express": "*" + } + }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", @@ -322,8 +319,7 @@ "@types/long": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==", - "optional": true + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" }, "@types/mime": { "version": "2.0.1", @@ -441,7 +437,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "optional": true, "requires": { "event-target-shim": "^5.0.0" } @@ -471,7 +466,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", - "optional": true, "requires": { "debug": "4" }, @@ -480,7 +474,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "optional": true, "requires": { "ms": "^2.1.1" } @@ -488,8 +481,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "optional": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -554,8 +546,7 @@ "arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "optional": true + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" }, "astral-regex": { "version": "1.0.0", @@ -572,14 +563,12 @@ "base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", - "optional": true + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, "bignumber.js": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", - "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", - "optional": true + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" }, "body-parser": { "version": "1.19.0", @@ -619,12 +608,6 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "optional": true }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -683,12 +666,6 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, "compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -756,8 +733,7 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "optional": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cors": { "version": "2.8.5", @@ -839,7 +815,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "optional": true, "requires": { "object-keys": "^1.0.12" } @@ -862,12 +837,6 @@ "streamsearch": "0.1.2" } }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -890,7 +859,6 @@ "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "optional": true, "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -901,14 +869,12 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "optional": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -949,7 +915,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "optional": true, "requires": { "once": "^1.4.0" } @@ -964,7 +929,6 @@ "version": "1.17.4", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", - "optional": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -998,7 +962,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "optional": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -1182,8 +1145,7 @@ "event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "optional": true + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" }, "express": { "version": "4.17.1", @@ -1225,8 +1187,7 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "optional": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "external-editor": { "version": "3.1.0", @@ -1266,8 +1227,7 @@ "fast-text-encoding": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", - "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==", - "optional": true + "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==" }, "faye-websocket": { "version": "0.11.3", @@ -1419,8 +1379,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "optional": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -1431,7 +1390,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.3.1.tgz", "integrity": "sha512-DQOesWEx59/bm63lTX0uHDDXpGTW9oKqNsoigwCoRe2lOb5rFqxzHjLTa6aqEBecLcz69dHLw7rbS068z1fvIQ==", - "optional": true, "requires": { "abort-controller": "^3.0.0", "extend": "^3.0.2", @@ -1444,7 +1402,6 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-3.4.0.tgz", "integrity": "sha512-fizmBtCXHp8b7FZuzbgKaixO8DzsSYoEVmMgZIna7x8t6cfBF3eqirODWYxVbgmasA5qudCAKiszfB7yVwroIQ==", - "optional": true, "requires": { "gaxios": "^2.1.0", "json-bigint": "^0.3.0" @@ -1506,7 +1463,6 @@ "version": "5.10.1", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.10.1.tgz", "integrity": "sha512-rOlaok5vlpV9rSiUu5EpR0vVpc+PhN62oF4RyX/6++DG1VsaulAFEMlDYBLjJDDPI6OcNOCGAKy9UVB/3NIDXg==", - "optional": true, "requires": { "arrify": "^2.0.0", "base64-js": "^1.3.0", @@ -1546,7 +1502,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.4.tgz", "integrity": "sha512-S4blHBQWZRnEW44OcR7TL9WR+QCqByRvhNDZ/uuQfpxywfupikf/miba8js1jZi6ZOGv5slgSuoshCWh6EMDzg==", - "optional": true, "requires": { "node-forge": "^0.9.0" }, @@ -1554,8 +1509,7 @@ "node-forge": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz", - "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==", - "optional": true + "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==" } } }, @@ -1569,7 +1523,6 @@ "version": "4.1.4", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.4.tgz", "integrity": "sha512-VxirzD0SWoFUo5p8RDP8Jt2AGyOmyYcT/pOUgDKJCK+iSw0TMqwrVfY37RXTNmoKwrzmDHSk0GMT9FsgVmnVSA==", - "optional": true, "requires": { "gaxios": "^2.1.0", "google-p12-pem": "^2.0.0", @@ -1580,8 +1533,7 @@ "mime": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", - "optional": true + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" } } }, @@ -1589,7 +1541,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "optional": true, "requires": { "function-bind": "^1.1.1" } @@ -1603,8 +1554,7 @@ "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "optional": true + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "hash-stream-validation": { "version": "0.2.2", @@ -1697,7 +1647,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "optional": true, "requires": { "agent-base": "6", "debug": "4" @@ -1707,7 +1656,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "optional": true, "requires": { "ms": "^2.1.1" } @@ -1715,8 +1663,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "optional": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -1854,8 +1801,7 @@ "is-arguments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", - "optional": true + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" }, "is-bigint": { "version": "1.0.0", @@ -1872,14 +1818,12 @@ "is-callable": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "optional": true + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" }, "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "optional": true + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, "is-extglob": { "version": "2.1.1", @@ -1905,8 +1849,7 @@ "is-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", - "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", - "optional": true + "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==" }, "is-number-object": { "version": "1.0.4", @@ -1930,7 +1873,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "optional": true, "requires": { "has": "^1.0.3" } @@ -1938,14 +1880,12 @@ "is-set": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", - "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==", - "optional": true + "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==" }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "optional": true + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" }, "is-stream-ended": { "version": "0.1.4", @@ -1956,14 +1896,12 @@ "is-string": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "optional": true + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" }, "is-symbol": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "optional": true, "requires": { "has-symbols": "^1.0.1" } @@ -1971,8 +1909,7 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "optional": true + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "is-weakmap": { "version": "2.0.1", @@ -1989,8 +1926,7 @@ "isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "optional": true + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" }, "isexe": { "version": "2.0.0", @@ -2018,7 +1954,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz", "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=", - "optional": true, "requires": { "bignumber.js": "^7.0.0" } @@ -2077,7 +2012,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "optional": true, "requires": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -2088,7 +2022,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "optional": true, "requires": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" @@ -2165,14 +2098,12 @@ "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", - "optional": true + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "optional": true, "requires": { "yallist": "^3.0.2" } @@ -2284,8 +2215,7 @@ "node-fetch": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", - "optional": true + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" }, "node-forge": { "version": "0.7.4", @@ -2300,8 +2230,7 @@ "object-inspect": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "optional": true + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" }, "object-is": { "version": "1.0.2", @@ -2312,14 +2241,12 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "optional": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "optional": true, "requires": { "define-properties": "^1.1.2", "function-bind": "^1.1.1", @@ -2412,12 +2339,6 @@ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -2447,8 +2368,7 @@ "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "optional": true + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "progress": { "version": "2.0.3", @@ -2460,7 +2380,6 @@ "version": "6.8.8", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", - "optional": true, "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -2480,8 +2399,7 @@ "@types/node": { "version": "10.17.17", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.17.tgz", - "integrity": "sha512-gpNnRnZP3VWzzj5k3qrpRC6Rk3H/uclhAVo1aIvwzK5p5cOrs9yEyQ8H/HBsBY0u5rrWxXEiVPQ0dEB6pkjE8Q==", - "optional": true + "integrity": "sha512-gpNnRnZP3VWzzj5k3qrpRC6Rk3H/uclhAVo1aIvwzK5p5cOrs9yEyQ8H/HBsBY0u5rrWxXEiVPQ0dEB6pkjE8Q==" } } }, @@ -2498,7 +2416,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "optional": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -2508,7 +2425,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", - "optional": true, "requires": { "duplexify": "^4.1.1", "inherits": "^2.0.3", @@ -2519,7 +2435,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", - "optional": true, "requires": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", @@ -2560,7 +2475,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "optional": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -2583,15 +2497,6 @@ "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", "dev": true }, - "resolve": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", - "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2790,7 +2695,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", - "optional": true, "requires": { "stubs": "^3.0.0" } @@ -2798,8 +2702,7 @@ "stream-shift": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", - "optional": true + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" }, "streamsearch": { "version": "0.1.2", @@ -2832,7 +2735,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", - "optional": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -2842,7 +2744,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", - "optional": true, "requires": { "define-properties": "^1.1.3", "function-bind": "^1.1.1" @@ -2852,7 +2753,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -2883,8 +2783,7 @@ "stubs": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", - "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=", - "optional": true + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" }, "supports-color": { "version": "5.5.0", @@ -2961,7 +2860,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", - "optional": true, "requires": { "readable-stream": "2 || 3" } @@ -2985,44 +2883,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, - "tslint": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", - "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -3094,8 +2954,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "optional": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "utils-merge": { "version": "1.0.1", @@ -3209,8 +3068,7 @@ "xdg-basedir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "optional": true + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" }, "xtend": { "version": "4.0.2", @@ -3220,8 +3078,7 @@ "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "optional": true + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" } } } diff --git a/backend/functions/package.json b/backend/functions/package.json index 23f028a..435b75a 100644 --- a/backend/functions/package.json +++ b/backend/functions/package.json @@ -14,6 +14,7 @@ }, "main": "lib/index.js", "dependencies": { + "@types/cors": "^2.8.6", "body-parser": "^1.19.0", "cors": "^2.8.5", "express": "^4.17.1", diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index dee8e20..25d8647 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -16,6 +16,19 @@ const app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); +app.options('*', function (req, res) { + res.sendStatus(200); +}); + +app.use(function (req, res, next) { + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept'); + res.header('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS'); + res.header('Access-Control-Allow-Credentials', "true"); + res.header('Access-Control-Max-Age', '86400'); + next(); +}); + // for @kanade9 後々トークンをもっと簡単に取ってくる方法見つけたときにこの関数を変更すれば良いだけになる様に切り出しておく const getToken = (req: express.Request): string => { // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している From 18c9cfa7a697722aa9be53c49958457479300f94 Mon Sep 17 00:00:00 2001 From: reud Date: Tue, 10 Mar 2020 14:38:55 +0900 Subject: [PATCH 27/31] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E3=83=9F=E3=82=B9?= =?UTF-8?q?=E3=81=AE=E4=BF=AE=E6=AD=A3(=E8=AA=9E=E5=BD=99=E5=8A=9B)=20swag?= =?UTF-8?q?ger=E3=82=92=E5=85=83=E3=81=AB=E6=88=BB=E3=81=97=E3=81=9F?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/api.ts | 32 +++++++++++++++++--------------- frontend/src/gen/base.ts | 2 +- swagger.yaml | 3 ++- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index cfd7a1d..4ceaa97 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -16,9 +16,7 @@ const app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); -app.options('*', function (req, res) { - res.sendStatus(200); -}); + app.use(function (req, res, next) { res.header('Access-Control-Allow-Origin', '*'); @@ -29,6 +27,10 @@ app.use(function (req, res, next) { next(); }); +app.options('*', function (req, res) { + res.sendStatus(200); +}); + // for @kanade9 後々トークンをもっと簡単に取ってくる方法見つけたときにこの関数を変更すれば良いだけになる様に切り出しておく const getToken = (req: express.Request): string => { // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している @@ -58,7 +60,7 @@ async function Verification( } else { console.log("Error: Id token does not match 'query uid' "); // for @kanade9 sendは不要のはず・・・ - resp.status(401); + resp.sendStatus(401); } }); } catch (exception) { @@ -66,7 +68,7 @@ async function Verification( "Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again" ); console.log(exception); - resp.status(401); + resp.sendStatus(401); } } app.use(function( @@ -134,7 +136,7 @@ app.get( } catch (exception) { console.log("class not found probably wrong or empty query"); console.log(exception); - resp.status(404).send("Not Found"); + resp.sendStatus(404).send("Not Found"); return; } } @@ -179,12 +181,12 @@ app.post( .doc(body.name) .set(data); console.log(data); - resp.status(200).send(JSON.stringify({ status: "OK" })); + resp.sendStatus(200).send(JSON.stringify({ status: "OK" })); return; } catch (exception) { console.log("An error occurred. Class data cannot add in database"); console.log(exception); - resp.status(500).send("Internal Server Error"); + resp.sendStatus(500).send("Internal Server Error"); return; } } @@ -208,10 +210,10 @@ app.get("/comment", async (req: functions.Request, resp: express.Response) => { console.log( `No comment were found match with ${req.query["class_name"]}` ); - resp.status(404).send("Not Found"); + resp.sendStatus(404).send("Not Found"); return; } - resp.status(200).send(JSON.stringify(qss.data())); + resp.sendStatus(200).send(JSON.stringify(qss.data())); return; } else { const querySnapshot = await fdb @@ -230,7 +232,7 @@ app.get("/comment", async (req: functions.Request, resp: express.Response) => { } catch (exception) { console.log("class not found probably wrong or empty query"); console.log(exception); - resp.status(404).send("Not Found"); + resp.sendStatus(404).send("Not Found"); return; } }); @@ -266,12 +268,12 @@ app.post("/comment", async (req: functions.Request, resp: express.Response) => { .doc(token.uid) .set(data); console.log(data); - resp.status(200).send(JSON.stringify({ status: "OK" })); + resp.sendStatus(200).send(JSON.stringify({ status: "OK" })); return; } catch (exception) { console.log("An error occurred. Comment cannot add in database"); console.log(exception); - resp.status(500).send("Internal Server Error"); + resp.sendStatus(500).send("Internal Server Error"); return; } }); @@ -290,12 +292,12 @@ app.delete( .collection("comment") .doc(token.uid) .delete(); - resp.status(204).send({ status: "OK" }); + resp.sendStatus(204).send({ status: "OK" }); return; } catch (exception) { console.log("An error occurred. Comment cannot delete from database"); console.log(exception); - resp.status(500).send("Internal Server Error"); + resp.sendStatus(500).send("Internal Server Error"); return; } } diff --git a/frontend/src/gen/base.ts b/frontend/src/gen/base.ts index 0572d02..76e44ef 100644 --- a/frontend/src/gen/base.ts +++ b/frontend/src/gen/base.ts @@ -17,7 +17,7 @@ import { Configuration } from "./configuration"; // @ts-ignore import globalAxios, { AxiosPromise, AxiosInstance } from 'axios'; -export const BASE_PATH = "http://localhost:5000".replace(/\/+$/, ""); +export const BASE_PATH = "https://us-central1-pj-marowd.cloudfunctions.net/api".replace(/\/+$/, ""); /** * diff --git a/swagger.yaml b/swagger.yaml index 672385b..d48089b 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -4,8 +4,9 @@ info: version: "1.0.0" title: "フロント⇆バックエンド用リファレンス" - host: "us-central1-pj-marowd.cloudfunctions.net" +basePath: "/api" + schemes: - "https" paths: From 8bbcf40433c9e54872f320c59823debe32a9830b Mon Sep 17 00:00:00 2001 From: reud Date: Tue, 10 Mar 2020 15:51:32 +0900 Subject: [PATCH 28/31] =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB?= =?UTF-8?q?=E3=81=AE=E5=88=87=E3=82=8A=E5=88=86=E3=81=91=E3=80=81=E8=A8=B1?= =?UTF-8?q?=E5=8F=AF=E3=83=98=E3=83=83=E3=83=80=E3=81=AE=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/api.ts | 310 ++---------------- backend/functions/src/auth.ts | 37 +++ backend/functions/src/common.ts | 5 + backend/functions/src/cors.ts | 22 ++ .../functions/src/handler/api/classData.ts | 86 +++++ backend/functions/src/handler/api/comment.ts | 119 +++++++ backend/functions/src/logger.ts | 21 ++ backend/functions/src/utils.ts | 10 + backend/yarn.lock | 4 - 9 files changed, 323 insertions(+), 291 deletions(-) create mode 100644 backend/functions/src/auth.ts create mode 100644 backend/functions/src/common.ts create mode 100644 backend/functions/src/cors.ts create mode 100644 backend/functions/src/handler/api/classData.ts create mode 100644 backend/functions/src/handler/api/comment.ts create mode 100644 backend/functions/src/logger.ts create mode 100644 backend/functions/src/utils.ts delete mode 100644 backend/yarn.lock diff --git a/backend/functions/src/api.ts b/backend/functions/src/api.ts index 4ceaa97..6b34387 100644 --- a/backend/functions/src/api.ts +++ b/backend/functions/src/api.ts @@ -3,304 +3,40 @@ import * as functions from "firebase-functions"; import * as express from "express"; // for @kanade9 こうすればrequireなしでかけるはず import * as admin from "firebase-admin"; +// import前にInitializeする必要がある https://qiita.com/nerikosans/items/2960ff3b073919f5e64c +admin.initializeApp(functions.config().firebase); import * as bodyParser from "body-parser"; -import * as moment from "moment"; +import { CorsResolveMiddleWare, OptionHandler } from "./cors"; +import { Verification } from "./auth"; +import { LoginLogger, LogoutLogger } from "./logger"; +import { + GetClassDataHandler, + PostClassDataHandler +} from "./handler/api/classData"; +import { DeleteComment, GetComment, PostComment } from "./handler/api/comment"; -admin.initializeApp(functions.config().firebase); -const db = admin.database(); -const fdb = admin.firestore(); -const ref = db.ref("server/account-data/"); const app = express(); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); +// to resolve cors +app.use(CorsResolveMiddleWare); +app.options("*", OptionHandler); - -app.use(function (req, res, next) { - res.header('Access-Control-Allow-Origin', '*'); - res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept'); - res.header('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS'); - res.header('Access-Control-Allow-Credentials', "true"); - res.header('Access-Control-Max-Age', '86400'); - next(); -}); - -app.options('*', function (req, res) { - res.sendStatus(200); -}); - -// for @kanade9 後々トークンをもっと簡単に取ってくる方法見つけたときにこの関数を変更すれば良いだけになる様に切り出しておく -const getToken = (req: express.Request): string => { - // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している - console.log(`METOD: ${req.method}`); - console.log(`headers: ${JSON.stringify(req.headers)}`); - console.log(JSON.stringify(req.headers.authorization)); - return req.headers.authorization ? req.headers.authorization : ""; -}; - -async function Verification( - req: express.Request, - resp: express.Response, - next: () => void -) { - // for @kanade9 これでreq.headers.authorizationに値が入っているかどうか見てからtokenStrに値を設定出来る - const tokenStr = getToken(req); - console.log(`token: ${tokenStr}`); - try { - const token = await admin.auth().verifyIdToken(tokenStr); - // 送られてきたtokenを元にユーザを認証する。 - ref - .child("users/" + token.uid) - .once("value", (snapshot: { exists: () => boolean }) => { - // for @kanade9 多分booleanが返る https://stackoverflow.com/questions/42892486/what-to-do-when-snapshot-exists-returns-false - if (snapshot.exists()) { - next(); - } else { - console.log("Error: Id token does not match 'query uid' "); - // for @kanade9 sendは不要のはず・・・ - resp.sendStatus(401); - } - }); - } catch (exception) { - console.log( - "Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again" - ); - console.log(exception); - resp.sendStatus(401); - } -} -app.use(function( - req: express.Request, - resp: express.Response, - next: () => void -) { - resp.header("Access-Control-Allow-Origin", req.headers.origin); - resp.header( - "Access-Control-Allow-Headers", - "X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept" - ); - resp.header("Access-Control-Allow-Methods", "POST, GET,DELETE, OPTIONS"); - resp.header("Access-Control-Max-Age", "8640"); - next(); -}); +// for authentication app.use(Verification); -export const RegisterLog = functions.auth.user().onCreate(async user => { - console.log(`Hello ${user.displayName} logged in`); - - // データベースに書き込む。一意に定まるユーザのuidを主キーとして設定し、メアドと名前を格納する。 - // for @kanade9 Promiseが返ってくるっぽいのでasync/await使ったほうがいいと思う - await ref.child("users/" + user.uid).set({ - mail: user.email, - name: user.displayName - }); - return; -}); - -export const UnRegisterLog = functions.auth.user().onDelete(user => { - console.log(`Hello ${user.displayName} account deleted`); - ref.child("users/" + user.uid).remove(); - return; -}); - -app.options("*", function(req, res) { - res.sendStatus(200); -}); - -app.get( - "/class_data", - async (req: functions.Request, resp: express.Response) => { - console.log(`subject_query= ${req.query["class_name"]} `); - try { - // queryでクラス名が指定されなかった場合は全ての授業データを取得する - if (!req.query["class_name"]) { - const querySnapshot = await fdb.collection("ClassSummary").get(); - // for @kanade9 ここany型以外に出来ない?(recordsがany[]になるの厳しい・・・) elem.data()はfirestoreにあるレコードの認識なのでinterface作って、data: () => になってほしい! - const records = querySnapshot.docs.map((elem: { data: () => any }) => - elem.data() - ); - console.log(records); - resp.send(JSON.stringify(records)); - return; - } else { - const documentSnapshot = await fdb - .collection("ClassSummary") - .doc(req.query["class_name"]) - .get(); - const record = documentSnapshot.data(); - resp.send(JSON.stringify(record)); - return; - } - } catch (exception) { - console.log("class not found probably wrong or empty query"); - console.log(exception); - resp.sendStatus(404).send("Not Found"); - return; - } - } -); +app.get("/class_data", GetClassDataHandler); +app.post("/class_data", PostClassDataHandler); -app.post( - "/class_data", - async (req: functions.Request, resp: express.Response) => { - resp.setHeader("Content-Type", "text/plain"); - console.log("json received"); - // req.setEncoding('utf8'); - console.log(req.body["name"]); - const body = req.body; - console.log(body); - - // req.headers.authorization のオブジェクトが未定義となるためにts-ignore - const tokenStr = getToken(req); - const token = await admin.auth().verifyIdToken(tokenStr); - - const data = { - name: body.name, - faculty: body.faculty, - department: body.department, - fav_amount: 0, - grade: body.grade, - professor: body.professor, - is_random: body.is_random, - rating: 0, - term: body.term, - edited_by: token.uid, - created_at: moment() - .add(9, "h") - .format(), - updated_at: moment() - .add(9, "h") - .format() - }; - console.log(data); - try { - await fdb - .collection("ClassSummary") - .doc(body.name) - .set(data); - console.log(data); - resp.sendStatus(200).send(JSON.stringify({ status: "OK" })); - return; - } catch (exception) { - console.log("An error occurred. Class data cannot add in database"); - console.log(exception); - resp.sendStatus(500).send("Internal Server Error"); - return; - } - } -); - -app.get("/comment", async (req: functions.Request, resp: express.Response) => { - console.log(`subject_query= ${req.query["class_name"]}`); - try { - if (req.query["comment_id"]) { - // req.headers.authorization のオブジェクトが未定義となるためにts-ignore - const tokenStr = getToken(req); - const token = await admin.auth().verifyIdToken(tokenStr); - - const qss = await fdb - .collection("ClassSummary") - .doc(req.query["class_name"]) - .collection("comment") - .doc(token.uid) - .get(); - if (!qss.data()) { - console.log( - `No comment were found match with ${req.query["class_name"]}` - ); - resp.sendStatus(404).send("Not Found"); - return; - } - resp.sendStatus(200).send(JSON.stringify(qss.data())); - return; - } else { - const querySnapshot = await fdb - .collection("ClassSummary") - .doc(req.query["class_name"]) - .collection("comment") - .get(); - // for @kanade9 ここany型以外に出来ない?(recordsがany[]になるの厳しい・・・) elem.data()はfirestoreにあるレコードの認識なのでinterface作って、data: () => になってほしい! - const records = querySnapshot.docs.map((elem: { data: () => any }) => - elem.data() - ); - console.log(records); - resp.send(JSON.stringify(records)); - return; - } - } catch (exception) { - console.log("class not found probably wrong or empty query"); - console.log(exception); - resp.sendStatus(404).send("Not Found"); - return; - } -}); - -app.post("/comment", async (req: functions.Request, resp: express.Response) => { - console.log("json received"); - const body = req.body; - - const tokenStr = getToken(req); - const token = await admin.auth().verifyIdToken(tokenStr); - const data = { - // for @kanade9 eslintだと全角スペースを入れると怒られるのでご参考までに・・・(下の文章に含まれていたので消しました。) - // nameは授業名です。titleはコメントのタイトル ex. 神授業です!!等 - name: body.name, - title: body.title, - comment: body.comment, - created_at: moment() - .add(9, "h") - .format(), - updated_at: moment() - .add(9, "h") - .format(), - edited_by: token.uid, - image: body.image, - is_recommend: body.is_recommend - }; - // IDでなくユーザのuidを用いてデータベースに格納する - try { - await fdb - .collection("ClassSummary") - .doc(body.name) - .collection("comment") - .doc(token.uid) - .set(data); - console.log(data); - resp.sendStatus(200).send(JSON.stringify({ status: "OK" })); - return; - } catch (exception) { - console.log("An error occurred. Comment cannot add in database"); - console.log(exception); - resp.sendStatus(500).send("Internal Server Error"); - return; - } -}); - -app.delete( - "/comment", - async (req: functions.Request, resp: express.Response) => { - console.log(req.query["class_name"]); - - const tokenStr = getToken(req); - const token = await admin.auth().verifyIdToken(tokenStr); - try { - await fdb - .collection("ClassSummary") - .doc(req.query["class_name"]) - .collection("comment") - .doc(token.uid) - .delete(); - resp.sendStatus(204).send({ status: "OK" }); - return; - } catch (exception) { - console.log("An error occurred. Comment cannot delete from database"); - console.log(exception); - resp.sendStatus(500).send("Internal Server Error"); - return; - } - } -); +app.get("/comment", GetComment); +app.post("/comment", PostComment); +app.delete("/comment", DeleteComment); exports.api = functions.https.onRequest(app); + +// for logging +export const RegisterLog = functions.auth.user().onCreate(LoginLogger); +export const UnRegisterLog = functions.auth.user().onDelete(LogoutLogger); \ No newline at end of file diff --git a/backend/functions/src/auth.ts b/backend/functions/src/auth.ts new file mode 100644 index 0000000..a7a90f9 --- /dev/null +++ b/backend/functions/src/auth.ts @@ -0,0 +1,37 @@ +import * as express from "express"; +import { GetToken } from "./utils"; +import * as admin from "firebase-admin"; +import { Ref } from "./common"; + +export const Verification = async ( + req: express.Request, + resp: express.Response, + next: () => void +): Promise => { + // for @kanade9 これでreq.headers.authorizationに値が入っているかどうか見てからtokenStrに値を設定出来る + const tokenStr = GetToken(req); + console.log(`token: ${tokenStr}`); + try { + const token = await admin.auth().verifyIdToken(tokenStr); + // 送られてきたtokenを元にユーザを認証する。 + Ref.child("users/" + token.uid).once( + "value", + (snapshot: { exists: () => boolean }) => { + // for @kanade9 多分booleanが返る https://stackoverflow.com/questions/42892486/what-to-do-when-snapshot-exists-returns-false + if (snapshot.exists()) { + next(); + } else { + console.log("Error: Id token does not match 'query uid' "); + // for @kanade9 sendは不要のはず・・・ + resp.sendStatus(401); + } + } + ); + } catch (exception) { + console.log( + "Error: Firebase ID token has kid claim which does not correspond to a known public key. so get a fresh token from your client app and try again" + ); + console.log(exception); + resp.sendStatus(401); + } +}; diff --git a/backend/functions/src/common.ts b/backend/functions/src/common.ts new file mode 100644 index 0000000..180b3ee --- /dev/null +++ b/backend/functions/src/common.ts @@ -0,0 +1,5 @@ +import * as admin from "firebase-admin"; + +export const Database = admin.database(); +export const Firestore = admin.firestore(); +export const Ref = Database.ref("server/account-data/"); diff --git a/backend/functions/src/cors.ts b/backend/functions/src/cors.ts new file mode 100644 index 0000000..b522ebf --- /dev/null +++ b/backend/functions/src/cors.ts @@ -0,0 +1,22 @@ +import { NextFunction, Request, Response } from "express"; + +export const OptionHandler = (req: Request, res: Response): void => { + res.sendStatus(200); + return; +}; + +export const CorsResolveMiddleWare = ( + req: Request, + res: Response, + next: NextFunction +): void => { + res.header("Access-Control-Allow-Origin", "*"); + res.header( + "Access-Control-Allow-Headers", + "X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept, Authorization" + ); + res.header("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS"); + res.header("Access-Control-Allow-Credentials", "true"); + res.header("Access-Control-Max-Age", "86400"); + next(); +}; diff --git a/backend/functions/src/handler/api/classData.ts b/backend/functions/src/handler/api/classData.ts new file mode 100644 index 0000000..80bb47f --- /dev/null +++ b/backend/functions/src/handler/api/classData.ts @@ -0,0 +1,86 @@ +import * as functions from "firebase-functions"; +import * as express from "express"; +import { Firestore } from "../../common"; +import { GetToken } from "../../utils"; +import * as admin from "firebase-admin"; +import * as moment from "moment"; + +export const GetClassDataHandler = async ( + req: functions.Request, + resp: express.Response +): Promise => { + console.log(`subject_query= ${req.query["class_name"]} `); + try { + // queryでクラス名が指定されなかった場合は全ての授業データを取得する + if (!req.query["class_name"]) { + const querySnapshot = await Firestore.collection("ClassSummary").get(); + // for @kanade9 ここany型以外に出来ない?(recordsがany[]になるの厳しい・・・) elem.data()はfirestoreにあるレコードの認識なのでinterface作って、data: () => になってほしい! + const records = querySnapshot.docs.map((elem: { data: () => any }) => + elem.data() + ); + console.log(records); + resp.send(JSON.stringify(records)); + return; + } else { + const documentSnapshot = await Firestore.collection("ClassSummary") + .doc(req.query["class_name"]) + .get(); + const record = documentSnapshot.data(); + resp.send(JSON.stringify(record)); + return; + } + } catch (exception) { + console.log("class not found probably wrong or empty query"); + console.log(exception); + resp.sendStatus(404).send("Not Found"); + return; + } +}; + +export const PostClassDataHandler = async ( + req: functions.Request, + resp: express.Response +): Promise => { + resp.setHeader("Content-Type", "text/plain"); + console.log("json received"); + // req.setEncoding('utf8'); + console.log(req.body["name"]); + const body = req.body; + console.log(body); + + const tokenStr = GetToken(req); + const token = await admin.auth().verifyIdToken(tokenStr); + + const data = { + name: body.name, + faculty: body.faculty, + department: body.department, + fav_amount: 0, + grade: body.grade, + professor: body.professor, + is_random: body.is_random, + rating: 0, + term: body.term, + edited_by: token.uid, + created_at: moment() + .add(9, "h") + .format(), + updated_at: moment() + .add(9, "h") + .format() + }; + console.log(data); + try { + await Firestore.collection("ClassSummary") + .doc(body.name) + .set(data); + console.log(data); + resp.sendStatus(200); + return; + } catch (exception) { + console.log("An error occurred. Class data cannot add in database"); + console.log(exception); + resp.sendStatus(500); + return; + } +}; diff --git a/backend/functions/src/handler/api/comment.ts b/backend/functions/src/handler/api/comment.ts new file mode 100644 index 0000000..76db3d0 --- /dev/null +++ b/backend/functions/src/handler/api/comment.ts @@ -0,0 +1,119 @@ +import * as functions from "firebase-functions"; +import * as express from "express"; +import { GetToken } from "../../utils"; +import * as admin from "firebase-admin"; +import { Firestore } from "../../common"; +import * as moment from "moment"; + +export const GetComment = async ( + req: functions.Request, + resp: express.Response +): Promise => { + console.log(`subject_query= ${req.query["class_name"]}`); + try { + if (req.query["comment_id"]) { + // req.headers.authorization のオブジェクトが未定義となるためにts-ignore + const tokenStr = GetToken(req); + const token = await admin.auth().verifyIdToken(tokenStr); + + const qss = await Firestore.collection("ClassSummary") + .doc(req.query["class_name"]) + .collection("comment") + .doc(token.uid) + .get(); + if (!qss.data()) { + console.log( + `No comment were found match with ${req.query["class_name"]}` + ); + resp.sendStatus(404).send("Not Found"); + return; + } + resp.sendStatus(200).send(JSON.stringify(qss.data())); + return; + } else { + const querySnapshot = await Firestore.collection("ClassSummary") + .doc(req.query["class_name"]) + .collection("comment") + .get(); + // for @kanade9 ここany型以外に出来ない?(recordsがany[]になるの厳しい・・・) elem.data()はfirestoreにあるレコードの認識なのでinterface作って、data: () => になってほしい! + const records = querySnapshot.docs.map((elem: { data: () => any }) => + elem.data() + ); + console.log(records); + resp.send(JSON.stringify(records)); + return; + } + } catch (exception) { + console.log("class not found probably wrong or empty query"); + console.log(exception); + resp.sendStatus(404).send("Not Found"); + return; + } +}; + +export const PostComment = async ( + req: functions.Request, + resp: express.Response +): Promise => { + console.log("json received"); + const body = req.body; + + const tokenStr = GetToken(req); + const token = await admin.auth().verifyIdToken(tokenStr); + const data = { + // for @kanade9 eslintだと全角スペースを入れると怒られるのでご参考までに・・・(下の文章に含まれていたので消しました。) + // nameは授業名です。titleはコメントのタイトル ex. 神授業です!!等 + name: body.name, + title: body.title, + comment: body.comment, + created_at: moment() + .add(9, "h") + .format(), + updated_at: moment() + .add(9, "h") + .format(), + edited_by: token.uid, + image: body.image, + is_recommend: body.is_recommend + }; + // IDでなくユーザのuidを用いてデータベースに格納する + try { + await Firestore.collection("ClassSummary") + .doc(body.name) + .collection("comment") + .doc(token.uid) + .set(data); + console.log(data); + resp.sendStatus(200).send(JSON.stringify({ status: "OK" })); + return; + } catch (exception) { + console.log("An error occurred. Comment cannot add in database"); + console.log(exception); + resp.sendStatus(500).send("Internal Server Error"); + return; + } +}; + +export const DeleteComment = async ( + req: functions.Request, + resp: express.Response +): Promise => { + console.log(req.query["class_name"]); + + const tokenStr = GetToken(req); + const token = await admin.auth().verifyIdToken(tokenStr); + try { + await Firestore.collection("ClassSummary") + .doc(req.query["class_name"]) + .collection("comment") + .doc(token.uid) + .delete(); + resp.sendStatus(204); + return; + } catch (exception) { + console.log("An error occurred. Comment cannot delete from database"); + console.log(exception); + resp.sendStatus(500); + return; + } +}; diff --git a/backend/functions/src/logger.ts b/backend/functions/src/logger.ts new file mode 100644 index 0000000..c608c61 --- /dev/null +++ b/backend/functions/src/logger.ts @@ -0,0 +1,21 @@ +import { Ref } from "./common"; + +// TODO:ここの型パッと思いつかなかったのでいったんany,後で変更予定 +export const LoginLogger = async (user: any): Promise => { + console.log(`Hello ${user.displayName} logged in`); + + // データベースに書き込む。一意に定まるユーザのuidを主キーとして設定し、メアドと名前を格納する。 + // for @kanade9 Promiseが返ってくるっぽいのでasync/await使ったほうがいいと思う + await Ref.child("users/" + user.uid).set({ + mail: user.email, + name: user.displayName + }); + return; +}; + +// TODO:ここの型パッと思いつかなかったのでいったんany,後で変更予定 +export const LogoutLogger = async (user: any): Promise => { + console.log(`Hello ${user.displayName} account deleted`); + Ref.child("users/" + user.uid).remove(); + return; +}; diff --git a/backend/functions/src/utils.ts b/backend/functions/src/utils.ts new file mode 100644 index 0000000..62c6eec --- /dev/null +++ b/backend/functions/src/utils.ts @@ -0,0 +1,10 @@ +// for @kanade9 後々トークンをもっと簡単に取ってくる方法見つけたときにこの関数を変更すれば良いだけになる様に切り出しておく +import { Request } from "express"; + +export const GetToken = (req: Request): string => { + // AuthorizationヘッダーはBearer の形式のため、id_tokenを取り出すために7文字目以降の文字列を切り出している + console.log(`METOD: ${req.method}`); + console.log(`headers: ${JSON.stringify(req.headers)}`); + console.log(JSON.stringify(req.headers.authorization)); + return req.headers.authorization ? req.headers.authorization : ""; +}; diff --git a/backend/yarn.lock b/backend/yarn.lock deleted file mode 100644 index fb57ccd..0000000 --- a/backend/yarn.lock +++ /dev/null @@ -1,4 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - From 7efbd4143d3394e2833ea3baa8db7ff695edb148 Mon Sep 17 00:00:00 2001 From: reud Date: Tue, 10 Mar 2020 15:59:19 +0900 Subject: [PATCH 29/31] =?UTF-8?q?token=E3=81=AE=E5=88=87=E3=82=8A=E5=87=BA?= =?UTF-8?q?=E3=81=97=E6=96=B9=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/utils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/functions/src/utils.ts b/backend/functions/src/utils.ts index 62c6eec..fc0288d 100644 --- a/backend/functions/src/utils.ts +++ b/backend/functions/src/utils.ts @@ -6,5 +6,6 @@ export const GetToken = (req: Request): string => { console.log(`METOD: ${req.method}`); console.log(`headers: ${JSON.stringify(req.headers)}`); console.log(JSON.stringify(req.headers.authorization)); - return req.headers.authorization ? req.headers.authorization : ""; + // req.headers.authorization.split(" ")[1]でBearer以降の文字列を取り出している。 + return req.headers.authorization ? req.headers.authorization.split(" ")[1] : ""; }; From 75c2b1ff615043b4c6a9164dce5b94e39fd9f464 Mon Sep 17 00:00:00 2001 From: kzmaro Date: Sat, 14 Mar 2020 12:33:44 +0900 Subject: [PATCH 30/31] =?UTF-8?q?=E3=83=AC=E3=82=B9=E3=83=9D=E3=83=B3?= =?UTF-8?q?=E3=82=B9=E3=83=98=E3=83=83=E3=83=80=E3=81=AE=E3=82=A8=E3=83=A9?= =?UTF-8?q?=E3=83=BC=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/handler/api/classData.ts | 2 +- backend/functions/src/handler/api/comment.ts | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/backend/functions/src/handler/api/classData.ts b/backend/functions/src/handler/api/classData.ts index 80bb47f..b97698e 100644 --- a/backend/functions/src/handler/api/classData.ts +++ b/backend/functions/src/handler/api/classData.ts @@ -32,7 +32,7 @@ export const GetClassDataHandler = async ( } catch (exception) { console.log("class not found probably wrong or empty query"); console.log(exception); - resp.sendStatus(404).send("Not Found"); + resp.sendStatus(404); return; } }; diff --git a/backend/functions/src/handler/api/comment.ts b/backend/functions/src/handler/api/comment.ts index 76db3d0..ae0d97f 100644 --- a/backend/functions/src/handler/api/comment.ts +++ b/backend/functions/src/handler/api/comment.ts @@ -25,10 +25,10 @@ export const GetComment = async ( console.log( `No comment were found match with ${req.query["class_name"]}` ); - resp.sendStatus(404).send("Not Found"); + resp.sendStatus(404); return; } - resp.sendStatus(200).send(JSON.stringify(qss.data())); + resp.send(JSON.stringify(qss.data())); return; } else { const querySnapshot = await Firestore.collection("ClassSummary") @@ -46,7 +46,7 @@ export const GetComment = async ( } catch (exception) { console.log("class not found probably wrong or empty query"); console.log(exception); - resp.sendStatus(404).send("Not Found"); + resp.sendStatus(404); return; } }; @@ -57,6 +57,7 @@ export const PostComment = async ( ): Promise => { console.log("json received"); const body = req.body; + console.log(body); const tokenStr = GetToken(req); const token = await admin.auth().verifyIdToken(tokenStr); @@ -84,12 +85,12 @@ export const PostComment = async ( .doc(token.uid) .set(data); console.log(data); - resp.sendStatus(200).send(JSON.stringify({ status: "OK" })); + resp.sendStatus(200); return; } catch (exception) { console.log("An error occurred. Comment cannot add in database"); console.log(exception); - resp.sendStatus(500).send("Internal Server Error"); + resp.sendStatus(500); return; } }; From 98ce96bd4aba409df1cebc0e10ba509cd505fb0a Mon Sep 17 00:00:00 2001 From: kzmaro Date: Sat, 14 Mar 2020 14:04:11 +0900 Subject: [PATCH 31/31] =?UTF-8?q?=E3=83=AC=E3=82=B9=E3=83=9D=E3=83=B3?= =?UTF-8?q?=E3=82=B9=E3=83=98=E3=83=83=E3=83=80=E3=81=AE=E3=82=A8=E3=83=A9?= =?UTF-8?q?=E3=83=BC=E3=81=AE=E4=BF=AE=E6=AD=A3=E3=80=80=E5=86=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/functions/src/handler/api/classData.ts | 4 ++-- backend/functions/src/handler/api/comment.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/functions/src/handler/api/classData.ts b/backend/functions/src/handler/api/classData.ts index b97698e..c95e9ce 100644 --- a/backend/functions/src/handler/api/classData.ts +++ b/backend/functions/src/handler/api/classData.ts @@ -19,14 +19,14 @@ export const GetClassDataHandler = async ( elem.data() ); console.log(records); - resp.send(JSON.stringify(records)); + resp.status(200).send(JSON.stringify(records)); return; } else { const documentSnapshot = await Firestore.collection("ClassSummary") .doc(req.query["class_name"]) .get(); const record = documentSnapshot.data(); - resp.send(JSON.stringify(record)); + resp.status(200).send(JSON.stringify(record)); return; } } catch (exception) { diff --git a/backend/functions/src/handler/api/comment.ts b/backend/functions/src/handler/api/comment.ts index ae0d97f..cce3c72 100644 --- a/backend/functions/src/handler/api/comment.ts +++ b/backend/functions/src/handler/api/comment.ts @@ -28,7 +28,7 @@ export const GetComment = async ( resp.sendStatus(404); return; } - resp.send(JSON.stringify(qss.data())); + resp.status(200).send(JSON.stringify(qss.data())); return; } else { const querySnapshot = await Firestore.collection("ClassSummary") @@ -40,7 +40,7 @@ export const GetComment = async ( elem.data() ); console.log(records); - resp.send(JSON.stringify(records)); + resp.status(200).send(JSON.stringify(records)); return; } } catch (exception) {