Convert lib/auth/server to typescript

Change-type: patch
This commit is contained in:
Pagan Gazzard 2020-02-05 21:07:49 +00:00
parent af86ac73e6
commit 93ba5832d8
5 changed files with 205 additions and 102 deletions

View File

@ -1,101 +0,0 @@
###
Copyright 2016 Balena
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
###
express = require('express')
path = require('path')
bodyParser = require('body-parser')
Promise = require('bluebird')
balena = require('balena-sdk').fromSharedOptions()
utils = require('./utils')
createServer = ({ port, isDev } = {}) ->
app = express()
app.use bodyParser.urlencoded
extended: true
app.set('view engine', 'ejs')
app.set('views', path.join(__dirname, 'pages'))
if isDev
app.use(express.static(path.join(__dirname, 'pages', 'static')))
server = app.listen(port)
return { app, server }
###*
# @summary Await for token
# @function
# @protected
#
# @param {Object} options - options
# @param {String} options.path - callback path
# @param {Number} options.port - http port
#
# @example
# server.awaitForToken
# path: '/auth'
# port: 9001
# .then (token) ->
# console.log(token)
###
exports.awaitForToken = (options) ->
{ app, server } = createServer(port: options.port)
return new Promise (resolve, reject) ->
closeServer = (errorMessage, successPayload) ->
server.close ->
if errorMessage
reject(new Error(errorMessage))
return
resolve(successPayload)
renderAndDone = ({ request, response, viewName, errorMessage, statusCode, token }) ->
return getContext(viewName)
.then (context) ->
response.status(statusCode || 200).render(viewName, context)
request.connection.destroy()
closeServer(errorMessage, token)
app.post options.path, (request, response) ->
token = request.body.token?.trim()
Promise.try ->
if not token
throw new Error('No token')
return utils.loginIfTokenValid(token)
.tap (loggedIn) ->
if not loggedIn
throw new Error('Invalid token')
.then ->
renderAndDone({ request, response, viewName: 'success', token })
.catch (error) ->
renderAndDone({
request, response, viewName: 'error',
statusCode: 401, errorMessage: error.message
})
app.use (request, response) ->
response.status(404).send('Not found')
closeServer('Unknown path or verb')
exports.getContext = getContext = (viewName) ->
if viewName is 'success'
return Promise.props
dashboardUrl: balena.settings.get('dashboardUrl')
return Promise.resolve({})

138
lib/auth/server.ts Normal file
View File

@ -0,0 +1,138 @@
/*
Copyright 2016 Balena
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import * as balenaSdk from 'balena-sdk';
import * as Promise from 'bluebird';
import * as bodyParser from 'body-parser';
import * as express from 'express';
import * as path from 'path';
import * as utils from './utils';
const balena = balenaSdk.fromSharedOptions();
const createServer = ({ port }: { port: number }) => {
const app = express();
app.use(
bodyParser.urlencoded({
extended: true,
}),
);
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'pages'));
const server = app.listen(port);
return { app, server };
};
/**
* @summary Await for token
* @function
* @protected
*
* @param {Object} options - options
* @param {String} options.path - callback path
* @param {Number} options.port - http port
*
* @example
* server.awaitForToken
* path: '/auth'
* port: 9001
* .then (token) ->
* console.log(token)
*/
export const awaitForToken = (options: {
path: string;
port: number;
}): Promise<string> => {
const { app, server } = createServer({ port: options.port });
return new Promise<string>((resolve, reject) => {
const closeServer = (
errorMessage: string | undefined,
successPayload?: string,
) => {
server.close(() => {
if (errorMessage) {
reject(new Error(errorMessage));
return;
}
resolve(successPayload);
});
};
const renderAndDone = async ({
request,
response,
viewName,
errorMessage,
statusCode = 200,
token,
}: {
request: express.Request;
response: express.Response;
viewName: 'success' | 'error';
errorMessage?: string;
statusCode?: number;
token?: string;
}) => {
const context = await getContext(viewName);
response.status(statusCode).render(viewName, context);
request.connection.destroy();
closeServer(errorMessage, token);
};
app.post(options.path, async (request, response) => {
try {
const token = request.body.token?.trim();
if (!token) {
throw new Error('No token');
}
const loggedIn = await utils.loginIfTokenValid(token);
if (!loggedIn) {
throw new Error('Invalid token');
}
await renderAndDone({ request, response, viewName: 'success', token });
} catch (error) {
await renderAndDone({
request,
response,
viewName: 'error',
statusCode: 401,
errorMessage: error.message,
});
}
});
app.use((_request, response) => {
response.status(404).send('Not found');
closeServer('Unknown path or verb');
});
});
};
export const getContext = (viewName: 'success' | 'error') => {
if (viewName === 'success') {
return Promise.props({
dashboardUrl: balena.settings.get('dashboardUrl'),
});
}
return Promise.resolve({});
};

62
npm-shrinkwrap.json generated
View File

@ -594,6 +594,16 @@
"resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.29.tgz",
"integrity": "sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw=="
},
"@types/body-parser": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.1.tgz",
"integrity": "sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==",
"dev": true,
"requires": {
"@types/connect": "*",
"@types/node": "*"
}
},
"@types/caseless": {
"version": "0.12.2",
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
@ -635,6 +645,15 @@
"resolved": "https://registry.npmjs.org/@types/common-tags/-/common-tags-1.8.0.tgz",
"integrity": "sha512-htRqZr5qn8EzMelhX/Xmx142z218lLyGaeZ3YR8jlze4TATRU9huKKvuBmAJEW4LCC4pnY1N6JAm6p85fMHjhg=="
},
"@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==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/depcheck": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@types/depcheck/-/depcheck-0.6.0.tgz",
@ -676,6 +695,27 @@
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g=="
},
"@types/express": {
"version": "4.17.2",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.2.tgz",
"integrity": "sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==",
"dev": true,
"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==",
"dev": true,
"requires": {
"@types/node": "*",
"@types/range-parser": "*"
}
},
"@types/form-data": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz",
@ -754,6 +794,12 @@
"resolved": "https://registry.npmjs.org/@types/memoizee/-/memoizee-0.4.3.tgz",
"integrity": "sha512-N6QT0c9ZbEKl33n1wyoTxZs4cpN+YXjs0Aqy5Qim8ipd9PBNIPqOh/p5Pixc4601tqr5GErsdxUbfqviDfubNw=="
},
"@types/mime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz",
"integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==",
"dev": true
},
"@types/minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
@ -846,6 +892,12 @@
"integrity": "sha1-ExqJDe1kIbG1RfRRCkrqvG1GUnU=",
"dev": true
},
"@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==",
"dev": true
},
"@types/raven": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@types/raven/-/raven-2.5.1.tgz",
@ -888,6 +940,16 @@
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz",
"integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ=="
},
"@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==",
"dev": true,
"requires": {
"@types/express-serve-static-core": "*",
"@types/mime": "*"
}
},
"@types/shell-escape": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@types/shell-escape/-/shell-escape-0.2.0.tgz",

View File

@ -98,12 +98,14 @@
"@octokit/rest": "^16.38.1",
"@types/archiver": "2.1.2",
"@types/bluebird": "^3.5.29",
"@types/body-parser": "^1.17.1",
"@types/chai": "^4.2.7",
"@types/chai-as-promised": "^7.1.1",
"@types/chokidar": "^1.7.5",
"@types/common-tags": "^1.8.0",
"@types/dockerode": "2.5.6",
"@types/ejs": "^3.0.0",
"@types/express": "^4.17.2",
"@types/fs-extra": "7.0.0",
"@types/intercept-stdout": "^0.1.0",
"@types/is-root": "1.0.0",

View File

@ -25,7 +25,9 @@ const options = {
path: '/auth',
};
const getPage = function(name: string): Promise<string> {
const getPage = function(
name: Parameters<typeof server.getContext>[0],
): Promise<string> {
const pagePath = path.join(
__dirname,
'..',