-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add frontend api for snapshots upload
- Loading branch information
Showing
15 changed files
with
270 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/* | ||
* Copyright (c) 2019, salesforce.com, inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: MIT | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT | ||
*/ | ||
|
||
import { ApiDBAdapter, TemporarySnapshot } from '../../types' | ||
import { ApiDatabaseConfig } from '@best/types'; | ||
import fetch from 'node-fetch'; | ||
|
||
/** | ||
* An implementation for a REST-based DB adapter. | ||
* It provides a way to save snapshots using a REST API provided by the frontend. | ||
*/ | ||
export default class FrontendRestDbAdapter extends ApiDBAdapter { | ||
config: ApiDatabaseConfig | ||
|
||
constructor(config: ApiDatabaseConfig) { | ||
super(config); | ||
this.config = config; | ||
} | ||
|
||
async saveSnapshots(snapshots: TemporarySnapshot[], projectName: string): Promise<boolean> { | ||
const requestUrl = `${this.config.uri}/api/v1/${projectName}/snapshots`; | ||
|
||
const response = await fetch(requestUrl, { | ||
method: 'post', | ||
body: JSON.stringify(snapshots), | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'Authorization': `Bearer ${this.config.token}` | ||
}, | ||
}); | ||
|
||
// Log the response body for troubleshooting purposes | ||
if (!response.ok) { | ||
console.error(await response.text()); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
async migrate() { | ||
// The migrate() function is called during results publishing, but it is not needed here. | ||
// We just need to make it a no-op as the server-side implementation handles the migration. | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* Copyright (c) 2019, salesforce.com, inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: MIT | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT | ||
*/ | ||
import { Request, Response, NextFunction } from "express"; | ||
import jwt from 'jsonwebtoken'; | ||
|
||
const TOKEN_SECRET = process.env.TOKEN_SECRET as string; | ||
const REVOKED_TOKENS = (process.env.REVOKED_TOKENS || "").split("\n"); | ||
|
||
/** | ||
* Checks if the provided token has been revoked based on the revocation list provided | ||
* in process.env.REVOKED_TOKENS environmental variable | ||
* @param token The token to check if it has been revoked. | ||
* @returns true if token is revoked, otherwise false | ||
*/ | ||
function isRevoked(token: string): boolean { | ||
if (REVOKED_TOKENS.includes(token)) { | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* Function that verifies the token provided in the request header | ||
* and on successful authorization it will call the next function on the chain. | ||
* The secret token must be provided via process.env.TOKEN_SECRET | ||
*/ | ||
export function authorizeRequest(req: Request, res: Response, next: NextFunction): void { | ||
const { authorization: authHeader } = req.headers; | ||
const token = authHeader && authHeader.split(' ')[1] | ||
|
||
// Send unauthorized response if token is not provided in the request | ||
if (token == null) { | ||
res.sendStatus(401); | ||
return; | ||
} | ||
|
||
// Block request if token has been revoked | ||
if (isRevoked(token)) { | ||
res.sendStatus(403); | ||
return; | ||
} | ||
|
||
jwt.verify(token, TOKEN_SECRET, (err): void => { | ||
// Block request if token is invalid or expired | ||
if (err) { | ||
// eslint-disable-next-line no-console | ||
console.error(err); | ||
res.sendStatus(403); | ||
return; | ||
} | ||
|
||
next(); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* Copyright (c) 2019, salesforce.com, inc. | ||
* All rights reserved. | ||
* SPDX-License-Identifier: MIT | ||
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT | ||
*/ | ||
|
||
// Borrowed from https://github.com/facebook/jest | ||
|
||
/** | ||
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
'use strict'; | ||
|
||
const jwt = require('jsonwebtoken'); | ||
const readline = require("readline"); | ||
|
||
const rl = readline.createInterface({ | ||
input: process.stdin, | ||
output: process.stdout | ||
}); | ||
|
||
function generateNewToken() { | ||
rl.question("Who are you generating this token for? ", function (user) { | ||
rl.question("How long should this token last for? (e.g. '1 year', '2 days', '24 hours', '5 minutes') ", function (validFor) { | ||
const token = jwt.sign({ user }, process.env.TOKEN_SECRET, { expiresIn: validFor }); | ||
const expiration = new Date(jwt.decode(token).exp * 1000); | ||
console.log(`Token generated for '${user}' expires on ${expiration}:\n${token}`); | ||
rl.close(); | ||
}); | ||
}); | ||
} | ||
|
||
function verifyToken() { | ||
rl.question("Enter token: ", function (token) { | ||
try { | ||
const decoded = jwt.verify(token, process.env.TOKEN_SECRET); | ||
const user = decoded.user; | ||
const issueDate = new Date(decoded.iat * 1000); | ||
const expirationDate = new Date(decoded.exp * 1000); | ||
|
||
console.log(`Issued to: ${user}`); | ||
console.log(`Issued Date: ${issueDate}`); | ||
console.log(`Expiration Date: ${expirationDate}`); | ||
} catch (e) { | ||
if (e instanceof jwt.TokenExpiredError) { | ||
console.error(`Token expired on ${e.expiredAt}`); | ||
process.exit(1); | ||
} else if (e instanceof jwt.JsonWebTokenError) { | ||
console.error(`Unable to parse token: ${e.message}`); | ||
process.exit(2); | ||
} else { | ||
process.exit(100) | ||
} | ||
} finally { | ||
rl.close(); | ||
} | ||
}); | ||
} | ||
|
||
rl.question("(1) Generate New Token\n(2) Verify Existing Token\n(3) Exit\n", function (option) { | ||
if (option === "1") { | ||
generateNewToken(); | ||
} else if (option === "2") { | ||
verifyToken(); | ||
} | ||
}); |
Oops, something went wrong.