Typescript port (#16)
* Ported to typsecript * fix audit vulnerability * fix tests and add rimraf * Update typescript scripts and travis configs * Update path
This commit is contained in:
Родитель
26c9a64d08
Коммит
9e7e56a661
|
@ -61,3 +61,6 @@ typings/
|
|||
|
||||
# vs code configuration file
|
||||
.vscode/
|
||||
|
||||
# Typescript
|
||||
dist/
|
|
@ -1,4 +1,11 @@
|
|||
language: node_js
|
||||
|
||||
before_script:
|
||||
- npm run compile
|
||||
|
||||
script:
|
||||
- npm run test
|
||||
|
||||
node_js:
|
||||
- "node"
|
||||
- "lts/*"
|
10
index.js
10
index.js
|
@ -1,10 +0,0 @@
|
|||
const server = require('./lib/app')
|
||||
|
||||
const app = server({
|
||||
isProd: process.env.NODE_ENV === 'production',
|
||||
authClientId: process.env.AUTH_CLIENT_ID,
|
||||
authAudience: process.env.AUTH_AUDIENCE,
|
||||
authIssuer: process.env.AUTH_ISSUER
|
||||
})
|
||||
|
||||
app.listen(process.env.PORT || 3000)
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
19
package.json
19
package.json
|
@ -2,11 +2,12 @@
|
|||
"name": "platform-chaos-api",
|
||||
"version": "1.0.0",
|
||||
"description": "API for Platform Chaos",
|
||||
"main": "index.js",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"test": "npm run lint & mocha",
|
||||
"start": "node index.js"
|
||||
"lint": "npx tslint --project .",
|
||||
"test": "npm run lint && mocha dist/test/",
|
||||
"compile": "npm run cleanup && npx tsc",
|
||||
"cleanup": "rimraf dist/"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -25,6 +26,8 @@
|
|||
},
|
||||
"homepage": "https://github.com/azure/platform-chaos-api#readme",
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^5.2.5",
|
||||
"@types/node": "^10.10.3",
|
||||
"eslint": "^5.4.0",
|
||||
"eslint-config-standard": "^12.0.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
|
@ -32,15 +35,19 @@
|
|||
"eslint-plugin-promise": "^4.0.0",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"mocha": "^5.0.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"standard": "^12.0.1",
|
||||
"supertest": "^3.2.0"
|
||||
"supertest": "^3.2.0",
|
||||
"tslint": "^5.11.0",
|
||||
"tslint-config-standard": "^8.0.1",
|
||||
"typescript": "^3.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"azure-chaos": "^1.1.1",
|
||||
"body-parser": "^1.18.2",
|
||||
"express": "^4.16.2",
|
||||
"passport": "^0.4.0",
|
||||
"passport-azure-ad": "^3.0.10",
|
||||
"passport-azure-ad": "^4.0.0",
|
||||
"passport-http-bearer": "^1.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// const server = require('./lib/app')
|
||||
import server from './lib/app'
|
||||
|
||||
const app = server({
|
||||
authAudience: process.env.AUTH_AUDIENCE,
|
||||
authClientId: process.env.AUTH_CLIENT_ID,
|
||||
authIssuer: process.env.AUTH_ISSUER,
|
||||
isProd: process.env.NODE_ENV === 'production'
|
||||
})
|
||||
|
||||
app.listen(process.env.PORT || 3000)
|
|
@ -1,12 +1,13 @@
|
|||
const express = require('express')
|
||||
const bodyParser = require('body-parser')
|
||||
const passport = require('passport')
|
||||
const MockStrategy = require('passport-http-bearer').Strategy
|
||||
const BearerStrategy = require('passport-azure-ad').BearerStrategy
|
||||
const azureChaos = require('azure-chaos')
|
||||
const constants = require('../lib/constants')
|
||||
import * as azureChaos from 'azure-chaos'
|
||||
import * as bodyParser from 'body-parser'
|
||||
import * as express from 'express'
|
||||
import * as passport from 'passport'
|
||||
import { BearerStrategy } from 'passport-azure-ad'
|
||||
import { Strategy as MockStrategy } from 'passport-http-bearer'
|
||||
|
||||
module.exports = (opts) => {
|
||||
import constants from '../lib/constants'
|
||||
|
||||
export default (opts) => {
|
||||
// configure the factory for runtime
|
||||
// this injects our production dependencies
|
||||
azureChaos.factory.RequestProcessor.configure({
|
||||
|
@ -17,6 +18,7 @@ module.exports = (opts) => {
|
|||
fsLocation: './webapp-extension-store.json'
|
||||
})
|
||||
azureChaos.factory.Logger.configure({
|
||||
// tslint:disable-next-line
|
||||
logImpl: console.log
|
||||
})
|
||||
azureChaos.factory.AzureAuthenticator.configure({
|
||||
|
@ -30,18 +32,18 @@ module.exports = (opts) => {
|
|||
if (opts && opts.isProd) {
|
||||
// in production, use Bearer Strategy for auth
|
||||
passport.use(new BearerStrategy({
|
||||
identityMetadata: 'https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration',
|
||||
clientID: opts.authClientId,
|
||||
audience: opts.authAudience,
|
||||
clientID: opts.authClientId,
|
||||
identityMetadata: 'https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration',
|
||||
issuer: opts.authIssuer,
|
||||
loggingLevel: 'error'
|
||||
}, function (token, done) {
|
||||
}, (token, done) => {
|
||||
done(null, token)
|
||||
}))
|
||||
} else {
|
||||
// if !isProd the test suite is being run so mock authentication
|
||||
const mockStrategy = new MockStrategy(
|
||||
function (token, done) {
|
||||
(token, done) => {
|
||||
if (token === constants.MOCK_TOKEN) {
|
||||
done(null, {})
|
||||
} else {
|
||||
|
@ -56,7 +58,7 @@ module.exports = (opts) => {
|
|||
app.use(passport.authorize('oauth-bearer', { session: false }))
|
||||
|
||||
app.get('/extensions', (req, res) => {
|
||||
registry.getAll().then(exts => {
|
||||
registry.getAll().then((exts) => {
|
||||
res.status(200).send(exts)
|
||||
}, (err) => {
|
||||
res.status(500).send({ error: err })
|
||||
|
@ -65,7 +67,7 @@ module.exports = (opts) => {
|
|||
|
||||
app.get('/extensions/:extId', (req, res) => {
|
||||
registry.get({ extensionName: req.params.extId })
|
||||
.then(e => {
|
||||
.then((e) => {
|
||||
res.status(200).send(e)
|
||||
}, (err) => {
|
||||
res.status(500).send({ error: err })
|
||||
|
@ -80,13 +82,14 @@ module.exports = (opts) => {
|
|||
.get({ extensionName: req.params.extId })
|
||||
.then((ext) => {
|
||||
return proc.start({
|
||||
extensionUri: ext.uri,
|
||||
accessToken: req.body.accessToken,
|
||||
authKey: req.query.code,
|
||||
resources: req.body.resources,
|
||||
accessToken: req.body.accessToken
|
||||
extensionUri: ext.uri,
|
||||
resources: req.body.resources
|
||||
})
|
||||
}).then((res) => {
|
||||
res.status(res.statusCode).send(res.body)
|
||||
})
|
||||
.then((result) => {
|
||||
res.status(result.statusCode).send(result.body)
|
||||
}, (err) => {
|
||||
res.status(500).send({ error: err })
|
||||
})
|
||||
|
@ -100,13 +103,13 @@ module.exports = (opts) => {
|
|||
.get({ extensionName: req.params.extId })
|
||||
.then((ext) => {
|
||||
return proc.stop({
|
||||
extensionUri: ext.uri,
|
||||
accessToken: req.body.accessToken,
|
||||
authKey: req.query.code,
|
||||
resources: req.body.resources,
|
||||
accessToken: req.body.accessToken
|
||||
extensionUri: ext.uri,
|
||||
resources: req.body.resources
|
||||
})
|
||||
}).then((res) => {
|
||||
res.status(res.statusCode).send(res.body)
|
||||
}).then((result) => {
|
||||
res.status(result.statusCode).send(result.body)
|
||||
}, (err) => {
|
||||
res.status(500).send({ error: err })
|
||||
})
|
||||
|
@ -127,9 +130,9 @@ module.exports = (opts) => {
|
|||
// {name, uri, desc}
|
||||
app.post('/extensions', bodyParser.json(), (req, res) => {
|
||||
registry.register({
|
||||
extensionDesc: req.body.desc,
|
||||
extensionName: req.body.name,
|
||||
extensionUri: req.body.uri,
|
||||
extensionDesc: req.body.desc
|
||||
extensionUri: req.body.uri
|
||||
}).then(() => {
|
||||
res.status(200).end()
|
||||
}, (err) => {
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = {
|
||||
MOCK_TOKEN: 'mock-token'
|
||||
}
|
||||
export default {
|
||||
MOCK_TOKEN: 'mock-token'
|
||||
}
|
|
@ -1,120 +1,119 @@
|
|||
/* eslint-env node, mocha */
|
||||
const request = require('supertest')
|
||||
const fs = require('fs')
|
||||
const server = require('../lib/app')
|
||||
const constants = require('../lib/constants')
|
||||
|
||||
const app = server({ isProd: false })
|
||||
|
||||
const extensionsPath = `${__dirname}/../webapp-extension-store.json`
|
||||
const bearerToken = `bearer ${constants.MOCK_TOKEN}`
|
||||
|
||||
describe('GET /extensions', function () {
|
||||
before(function () {
|
||||
if (fs.existsSync(extensionsPath)) {
|
||||
fs.unlink(extensionsPath, function (error) {
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
console.log('Deleted extension store.')
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('should require authorization', function (done) {
|
||||
request(app)
|
||||
.get('/extensions')
|
||||
.expect(401, done)
|
||||
})
|
||||
|
||||
it('responds with an empty array because there are no registered extensions', function (done) {
|
||||
request(app)
|
||||
.get('/extensions')
|
||||
.set('Authorization', bearerToken)
|
||||
.expect(200, [], done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('POST /extensions', function () {
|
||||
before(function () {
|
||||
if (fs.existsSync(extensionsPath)) {
|
||||
fs.unlink(extensionsPath, function (error) {
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
console.log('Deleted extension store.')
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const body = {
|
||||
'name': 'test name',
|
||||
'uri': 'https://test.com',
|
||||
'desc': 'test desc'
|
||||
}
|
||||
|
||||
const body2 = {
|
||||
'name': 'test name2',
|
||||
'uri': 'https://test.com2',
|
||||
'desc': 'test desc2'
|
||||
}
|
||||
|
||||
it('should require authorization', function (done) {
|
||||
request(app)
|
||||
.post('/extensions')
|
||||
.send(body)
|
||||
.expect(401, done)
|
||||
})
|
||||
|
||||
it('creates a new extension with payload posted', function (done) {
|
||||
request(app)
|
||||
.post('/extensions')
|
||||
.set('Authorization', bearerToken)
|
||||
.set('Content-Type', 'application/json')
|
||||
.send(body)
|
||||
.expect(200, done)
|
||||
})
|
||||
|
||||
it('can get the extension that just registered', function (done) {
|
||||
request(app)
|
||||
.get('/extensions')
|
||||
.set('Authorization', bearerToken)
|
||||
.expect(200, [body], done)
|
||||
})
|
||||
|
||||
it('creates a second extension with payload posted', function (done) {
|
||||
request(app)
|
||||
.post('/extensions')
|
||||
.set('Authorization', bearerToken)
|
||||
.set('Content-Type', 'application/json')
|
||||
.send(body2)
|
||||
.expect(200, done)
|
||||
})
|
||||
|
||||
it('can get both of the registered extensions', function (done) {
|
||||
request(app)
|
||||
.get('/extensions')
|
||||
.set('Authorization', bearerToken)
|
||||
.expect(200, [body, body2], done)
|
||||
})
|
||||
|
||||
it('will not create an extension if name is duplicate', function (done) {
|
||||
request(app)
|
||||
.post('/extensions')
|
||||
.set('Authorization', bearerToken)
|
||||
.set('Content-Type', 'application/json')
|
||||
.send(body)
|
||||
.expect(500, done)
|
||||
})
|
||||
})
|
||||
|
||||
after(function () {
|
||||
if (fs.existsSync(extensionsPath)) {
|
||||
fs.unlink(extensionsPath, function (error) {
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
console.log('Deleted extension store.')
|
||||
})
|
||||
}
|
||||
})
|
||||
/* eslint-env node, mocha */
|
||||
import * as fs from 'fs'
|
||||
import * as request from 'supertest'
|
||||
|
||||
import server from '../lib/app'
|
||||
import constants from '../lib/constants'
|
||||
|
||||
const app = server({ isProd: false })
|
||||
|
||||
const extensionsPath = `${__dirname}/../../webapp-extension-store.json`
|
||||
const bearerToken = `bearer ${constants.MOCK_TOKEN}`
|
||||
|
||||
describe('GET /extensions', () => {
|
||||
before(() => {
|
||||
if (fs.existsSync(extensionsPath)) {
|
||||
fs.unlink(extensionsPath, (error) => {
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('should require authorization', (done) => {
|
||||
request(app)
|
||||
.get('/extensions')
|
||||
.expect(401, done)
|
||||
})
|
||||
|
||||
it('responds with an empty array because there are no registered extensions', (done) => {
|
||||
request(app)
|
||||
.get('/extensions')
|
||||
.set('Authorization', bearerToken)
|
||||
.expect(200, [], done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('POST /extensions', () => {
|
||||
before(() => {
|
||||
if (fs.existsSync(extensionsPath)) {
|
||||
fs.unlink(extensionsPath, (error) => {
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const body = {
|
||||
desc: 'test desc',
|
||||
name: 'test name',
|
||||
uri: 'https://test.com'
|
||||
}
|
||||
|
||||
const body2 = {
|
||||
desc: 'test desc2',
|
||||
name: 'test name2',
|
||||
uri: 'https://test.com2'
|
||||
}
|
||||
|
||||
it('should require authorization', (done) => {
|
||||
request(app)
|
||||
.post('/extensions')
|
||||
.send(body)
|
||||
.expect(401, done)
|
||||
})
|
||||
|
||||
it('creates a new extension with payload posted', (done) => {
|
||||
request(app)
|
||||
.post('/extensions')
|
||||
.set('Authorization', bearerToken)
|
||||
.set('Content-Type', 'application/json')
|
||||
.send(body)
|
||||
.expect(200, done)
|
||||
})
|
||||
|
||||
it('can get the extension that just registered', (done) => {
|
||||
request(app)
|
||||
.get('/extensions')
|
||||
.set('Authorization', bearerToken)
|
||||
.expect(200, [body], done)
|
||||
})
|
||||
|
||||
it('creates a second extension with payload posted', (done) => {
|
||||
request(app)
|
||||
.post('/extensions')
|
||||
.set('Authorization', bearerToken)
|
||||
.set('Content-Type', 'application/json')
|
||||
.send(body2)
|
||||
.expect(200, done)
|
||||
})
|
||||
|
||||
it('can get both of the registered extensions', (done) => {
|
||||
request(app)
|
||||
.get('/extensions')
|
||||
.set('Authorization', bearerToken)
|
||||
.expect(200, [body, body2], done)
|
||||
})
|
||||
|
||||
it('will not create an extension if name is duplicate', (done) => {
|
||||
request(app)
|
||||
.post('/extensions')
|
||||
.set('Authorization', bearerToken)
|
||||
.set('Content-Type', 'application/json')
|
||||
.send(body)
|
||||
.expect(500, done)
|
||||
})
|
||||
})
|
||||
|
||||
after(() => {
|
||||
if (fs.existsSync(extensionsPath)) {
|
||||
fs.unlink(extensionsPath, (error) => {
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["es6"],
|
||||
"module": "commonjs",
|
||||
"outDir": "dist",
|
||||
"sourceMap": true,
|
||||
"target": "es6",
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"extends": [
|
||||
"tslint:recommended",
|
||||
"tslint-config-standard"
|
||||
]
|
||||
}
|
Загрузка…
Ссылка в новой задаче