diff --git a/lib/classes/Service.js b/lib/classes/Service.js index 4894a4bca..bfc72cb04 100644 --- a/lib/classes/Service.js +++ b/lib/classes/Service.js @@ -133,6 +133,8 @@ class Service { that.service = serverlessFile.service; } + that.app = serverlessFile.app; + that.tenant = serverlessFile.tenant; that.custom = serverlessFile.custom; that.plugins = serverlessFile.plugins; that.resources = serverlessFile.resources; diff --git a/lib/plugins/login/lib/decryptToken.js b/lib/plugins/login/lib/decryptToken.js deleted file mode 100644 index 17e0b00e5..000000000 --- a/lib/plugins/login/lib/decryptToken.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -const forge = require('node-forge'); - -module.exports = (encryptedToken, key, iv) => { - const decipherToken = forge.cipher.createDecipher('AES-CBC', key); - decipherToken.start({ iv }); - decipherToken.update(forge.util.createBuffer(forge.util.decode64(encryptedToken))); - const result = decipherToken.finish(); // check 'result' for true/false - if (!result) { - throw new Error(`Couldn't decrypt token: ${encryptedToken}`); - } - return decipherToken.output.toString(); -}; diff --git a/lib/plugins/login/lib/decryptToken.test.js b/lib/plugins/login/lib/decryptToken.test.js deleted file mode 100644 index a9b71cde1..000000000 --- a/lib/plugins/login/lib/decryptToken.test.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -const expect = require('chai').expect; -const forge = require('node-forge'); -const decryptToken = require('./decryptToken'); - -const encryptAuthToken = (token, key, iv) => { - const cipher = forge.cipher.createCipher('AES-CBC', key); - cipher.start({ iv }); - cipher.update(forge.util.createBuffer(token)); - cipher.finish(); - return forge.util.encode64(cipher.output.data); -}; - -describe('#decryptToken()', () => { - it('should encrypt a token with AWS CBC', () => { - const token = 'f3120811-8306-4d67-98e5-13fde2e490e4'; - const key = forge.random.getBytesSync(16); - const iv = forge.random.getBytesSync(16); - const encryptedToken = encryptAuthToken(token, key, iv); - expect(decryptToken(encryptedToken, key, iv)).to.equal(token); - }); -}); diff --git a/lib/plugins/login/lib/getCliLoginById.js b/lib/plugins/login/lib/getCliLoginById.js deleted file mode 100644 index ae0104ba4..000000000 --- a/lib/plugins/login/lib/getCliLoginById.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -const gql = require('graphql-tag'); - -module.exports = (id, apolloQueryFn) => - apolloQueryFn({ - fetchPolicy: 'network-only', - query: gql` - query cliLoginById($id: String!) { - cliLoginById(id: $id) { - encryptedAccessToken - encryptedIdToken - encryptedRefreshToken - encryptedKey - encryptedIv - } - } - `, - variables: { id }, - }).then(response => response.data); diff --git a/lib/plugins/login/lib/getCliLoginById.test.js b/lib/plugins/login/lib/getCliLoginById.test.js deleted file mode 100644 index 3c739bcf8..000000000 --- a/lib/plugins/login/lib/getCliLoginById.test.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -const sinon = require('sinon'); -const expect = require('chai').expect; -const gql = require('graphql-tag'); -const getCliLoginById = require('./getCliLoginById'); - -describe('#getCliLoginById()', () => { - it('should query for the cliLoginById', () => { - const expectedParams = { - fetchPolicy: 'network-only', - query: gql` - query cliLoginById($id: String!) { - cliLoginById(id: $id) { - encryptedAccessToken - encryptedIdToken - encryptedRefreshToken - encryptedKey - encryptedIv - } - } - `, - variables: { id: 'abcd' }, - }; - - const query = sinon.stub().resolves({ data: { cliLoginId: 'abcd' } }); - return getCliLoginById('abcd', query).then(data => { - expect(data).to.deep.equal({ cliLoginId: 'abcd' }); - expect(query.getCall(0).args[0]).to.deep.equal(expectedParams); - }); - }); -}); diff --git a/lib/plugins/login/login.js b/lib/plugins/login/login.js index d1e6c1f2f..b6f1b25ef 100644 --- a/lib/plugins/login/login.js +++ b/lib/plugins/login/login.js @@ -2,26 +2,9 @@ const BbPromise = require('bluebird'); const jwtDecode = require('jwt-decode'); -const chalk = require('chalk'); -const uuid = require('uuid'); -const has = require('lodash/has'); -const forge = require('node-forge'); -const querystring = require('querystring'); -const openBrowser = require('../../utils/openBrowser'); +const platform = require('@serverless/platform-sdk'); const configUtils = require('../../utils/config'); -const clearConsole = require('../../utils/clearConsole'); const userStats = require('../../utils/userStats'); -const setConfig = require('../../utils/config').set; -const createApolloClient = require('../../utils/createApolloClient'); -const decryptToken = require('./lib/decryptToken'); -const getCliLoginById = require('./lib/getCliLoginById'); - -const config = { - PLATFORM_FRONTEND_BASE_URL: 'https://platform.serverless.com/', - GRAPHQL_ENDPOINT_URL: 'https://graphql.serverless.com/graphql', -}; - -const client = createApolloClient(config.GRAPHQL_ENDPOINT_URL); class Login { constructor(serverless, options) { @@ -41,136 +24,53 @@ class Login { }; } login() { - clearConsole(); this.serverless.cli.log('The Serverless login will open in your default browser...'); const configuration = configUtils.getConfig(); const frameworkId = configuration.frameworkId; - const cliLoginId = uuid.v4(); - let fetchTries = 0; - forge.pki.rsa.generateKeyPair({ bits: 2048 }, (generateKeyErr, keypair) => { - if (generateKeyErr) { - this.serverless.cli.log( - 'Sorry, failed initiating the authentication key. ', - 'Please contact the Serverless team at hello@serverless.com' - ); - throw generateKeyErr; - } - const publicKeyPem = forge.pki.publicKeyToPem(keypair.publicKey); - const encodedPublicKeyPem = forge.util.encode64(publicKeyPem); - - this.serverless.cli.log('Opening browser...'); - - // Avoid camel casing since queries is going into to be part of the URL - const queries = querystring.stringify({ - cli: 'v1', - 'login-id': cliLoginId, - 'public-key': encodedPublicKeyPem, - }); - // open default browser - openBrowser(`${config.PLATFORM_FRONTEND_BASE_URL}login?${queries}`); - - const fetchCliLogin = () => { - fetchTries += 1; - // indicating the user after a while that the CLI is still waiting - if (fetchTries >= 60) { - this.serverless.cli.log('Waiting for a successful authentication in the browser.'); - fetchTries = 0; - } - getCliLoginById(cliLoginId, client.query) - .then(response => { - const hasAllToken = - has(response, ['cliLoginById', 'encryptedAccessToken']) && - has(response, ['cliLoginById', 'encryptedIdToken']) && - has(response, ['cliLoginById', 'encryptedRefreshToken']) && - has(response, ['cliLoginById', 'encryptedKey']) && - has(response, ['cliLoginById', 'encryptedIv']) && - response.cliLoginById.encryptedAccessToken !== null && - response.cliLoginById.encryptedIdToken !== null && - response.cliLoginById.encryptedRefreshToken !== null && - response.cliLoginById.encryptedKey !== null && - response.cliLoginById.encryptedIv !== null; - if (!hasAllToken) { - // delay the requests for a bit - setTimeout(() => fetchCliLogin(), 500); - } else { - const key = keypair.privateKey.decrypt( - forge.util.decode64(response.cliLoginById.encryptedKey), - 'RSA-OAEP' - ); - const iv = keypair.privateKey.decrypt( - forge.util.decode64(response.cliLoginById.encryptedIv), - 'RSA-OAEP' - ); - - const idToken = decryptToken(response.cliLoginById.encryptedIdToken, key, iv); - const accessToken = decryptToken(response.cliLoginById.encryptedAccessToken, key, iv); - const refreshToken = decryptToken( - response.cliLoginById.encryptedRefreshToken, - key, - iv - ); - - const decoded = jwtDecode(idToken); - this.serverless.cli.log('You are now logged in'); - // because platform only support github - const id = decoded.tracking_id || decoded.sub; - const userConfig = { - userId: id, - frameworkId, - users: {}, - }; - // set user auth in global .serverlessrc file - userConfig.users[id] = { - userId: id, - name: decoded.name, - email: decoded.email, - auth: { - id_token: idToken, - access_token: accessToken, - refresh_token: refreshToken, - }, - }; - - // update .serverlessrc - setConfig(userConfig); - - // identify user for better onboarding - userStats - .identify({ - id, - frameworkId, - email: decoded.email, - // unix timestamp - created_at: Math.round(+new Date(decoded.createdAt) / 1000), - trackingDisabled: configuration.trackingDisabled, - force: true, - }) - .then(() => { - userStats - .track('user_loggedIn', { - id, - email: decoded.email, - force: true, - }) - .then(() => { - // then exit process - process.exit(0); - }); - }); - } - }) - .catch(() => { - this.serverless.cli.consoleLog( - chalk.red('Sorry, something went wrong. Please run "serverless login" again.') - ); - throw new this.serverless.classes.Error( - 'Failed to login due to an error. Please try again or contact hello@serverless.com' - ); - }); + return platform.login().then(data => { + const decoded = jwtDecode(data.idToken); + // because platform only support github + const id = decoded.tracking_id || decoded.sub; + const userConfig = { + userId: id, + frameworkId, + users: {}, + }; + // set user auth in global .serverlessrc file + userConfig.users[id] = { + userId: id, + name: decoded.name, + email: decoded.email, + username: decoded.nickname, + auth: configuration.users[id].auth, + dashboard: data, }; - fetchCliLogin(); + // update .serverlessrc + configUtils.set(userConfig); + + // identify user for better onboarding + userStats + .identify({ + id, + frameworkId, + email: decoded.email, + // unix timestamp + created_at: Math.round(+new Date(decoded.createdAt) / 1000), + trackingDisabled: configuration.trackingDisabled, + force: true, + }) + .then(() => { + userStats + .track('user_loggedIn', { + id, + email: decoded.email, + force: true, + }); + }); + this.serverless.cli.log('You are now logged in'); + process.exit(0); }); } } diff --git a/lib/plugins/logout/logout.js b/lib/plugins/logout/logout.js index 380668694..6a5073fcb 100644 --- a/lib/plugins/logout/logout.js +++ b/lib/plugins/logout/logout.js @@ -30,9 +30,9 @@ class Logout { // that invalidate a refresh token in Auth0 (using the Auth0 Management API). if (globalConfig && globalConfig.users && globalConfig.users[currentId]) { - if (globalConfig.users[currentId].auth) { + if (globalConfig.users[currentId].dashboard) { // remove auth tokens from user - configUtils.set(`users.${currentId}.auth`, null); + configUtils.set(`users.${currentId}.dashboard`, null); // log stat userStats.track('user_loggedOut').then(() => { this.serverless.cli.consoleLog('Successfully logged out.'); diff --git a/lib/plugins/platform/platform.js b/lib/plugins/platform/platform.js index 740915759..3ba329c6c 100644 --- a/lib/plugins/platform/platform.js +++ b/lib/plugins/platform/platform.js @@ -2,64 +2,21 @@ /* eslint-disable no-console */ -const path = require('path'); -const fs = require('fs'); -const gql = require('graphql-tag'); -const jwtDecode = require('jwt-decode'); const BbPromise = require('bluebird'); -const fsExtra = require('../../utils/fs/fse'); -const fetch = require('node-fetch'); -const chalk = require('chalk'); -const functionInfoUtils = require('../../utils/functionInfoUtils'); -const createApolloClient = require('../../utils/createApolloClient'); -const getAuthToken = require('../../utils/getAuthToken'); -const selectServicePublish = require('../../utils/selectors/selectServicePublish'); - -// NOTE Needed for apollo to work -global.fetch = fetch; - -const config = { - PLATFORM_FRONTEND_BASE_URL: 'https://platform.serverless.com/', - GRAPHQL_ENDPOINT_URL: 'https://graphql.serverless.com/graphql', -}; - -function addReadme(attributes, readmePath) { - if (fs.existsSync(readmePath)) { - const readmeContent = fsExtra.readFileSync(readmePath).toString('utf8'); - // eslint-disable-next-line no-param-reassign - attributes.readme = readmeContent; - } - return attributes; -} - -function fetchEndpoint(provider) { - return provider - .request( - 'CloudFormation', - 'describeStacks', - { StackName: provider.naming.getStackName() }, - { useCache: true } // Use request cache - ) - .then(result => { - let endpoint = null; - - if (result) { - result.Stacks[0].Outputs - .filter(x => x.OutputKey.match(provider.naming.getServiceEndpointRegex())) - .forEach(x => { - endpoint = x.OutputValue; - }); - } - - return endpoint; - }); -} +const crypto = require('crypto'); +const _ = require('lodash'); +const platform = require('@serverless/platform-sdk'); +const getAccessKey = require('../../utils/getAccessKey'); class Platform { constructor(serverless, options) { this.serverless = serverless; this.options = options; this.provider = this.serverless.getProvider('aws'); + this.config = { + app: this.serverless.service.app, + tenant: this.serverless.service.tenant, + }; // NOTE for the time being we only track services published to AWS if (this.provider) { this.hooks = { @@ -69,141 +26,120 @@ class Platform { } } - archiveServiceRequest(name, client) { - return client.mutate({ - mutation: gql` - mutation archiveService($name: String!) { - archiveService(name: $name) { - archived + publishService() { + return getAccessKey(this.config.tenant).then(accessKey => { + if (!accessKey || !this.config.app || !this.config.tenant) { + return BbPromise.resolve(); + } + + this.serverless.cli.log('Publishing service to Serverless Platform...'); + + const service = this.serverless.service; + + const data = { + app: this.config.app, + tenant: this.config.tenant, + accessKey, + version: '0.1.0', + service: this.getServiceData(), + functions: [], + subscriptions: [], + }; + + Object.keys(service.functions).forEach(fn => { + const fnObj = _.omit(service.functions[fn], ['events']); + fnObj.functionId = this.serverless.service.getFunction(fn).name; + data.functions.push(fnObj); + + this.serverless.service.getAllEventsInFunction(fn).forEach(event => { + const subscription = { + functionId: this.serverless.service.getFunction(fn).name, + }; + + // in case of sls custom event type... + if (typeof event === 'string') { + subscription.type = event; + subscription.subscriptionId = crypto.createHash('md5') + .update(`${subscription.functionId}-${event}`).digest('hex'); + // in case of aws apigateway + } else if (Object.keys(event)[0] === 'http') { + subscription.type = 'aws.apigateway.http'; + if (typeof event.http === 'string') { + // todo http shortcut + } else if (typeof event.http === 'object') { + subscription.method = event.http.method; + subscription.path = event.http.path; + subscription.subscriptionId = crypto.createHash('md5') + .update(JSON.stringify(subscription)).digest('hex'); + } } - } - `, - variables: { name }, + // todo support aws events and http + data.subscriptions.push(subscription); + }); + }); + + return new BbPromise((resolve, reject) => { + platform.publishService(data) + .then(() => { + this.serverless.cli + .log('Successfully published your service on the Serverless Platform'); + resolve(); + process.exit(0); + }) + .catch(err => { + this.serverless.cli.log('Failed to published your service on the Serverless Platform'); + reject(err.message); + }); + }); }); } + getServiceData() { + const serviceData = { + name: this.serverless.service.service, + stage: this.serverless.processedInput.options.stage + || this.serverless.service.provider.stage, + provider: this.serverless.service.provider, + }; + if (this.serverless.service.serviceObject.description) { + serviceData.description = this.serverless.service.serviceObject.description; + } + if (this.serverless.service.serviceObject.license) { + serviceData.license = this.serverless.service.serviceObject.license; + } + if (this.serverless.service.serviceObject.bugs) { + serviceData.bugs = this.serverless.service.serviceObject.bugs; + } + if (this.serverless.service.serviceObject.repository) { + serviceData.repository = this.serverless.service.serviceObject.repository; + } + if (this.serverless.service.serviceObject.homepage) { + serviceData.homepage = this.serverless.service.serviceObject.homepage; + } + return serviceData; + } + archiveService() { - const authToken = this.getAuthToken(); - const publishFlag = selectServicePublish(this.serverless.service); - if (!authToken || !publishFlag) { - // NOTE archiveService is an opt-in feature and no warning is needed - return BbPromise.resolve(); - } - - const clientWithAuth = createApolloClient(config.GRAPHQL_ENDPOINT_URL, authToken); - return this.archiveServiceRequest(this.serverless.service.service, clientWithAuth) - .then(response => { - this.serverless.cli.log('Successfully archived your service on the Serverless Platform'); - return response.data; - }) - .catch(err => { - this.serverless.cli.log('Failed to archived your service on the Serverless Platform'); - throw new this.serverless.classes.Error(err.message); - }); - } - - publishServiceRequest(service, client) { - return client - .mutate({ - mutation: gql` - mutation publishService($service: ServicePublishInputType!) { - publishService(service: $service) { - name - } - } - `, - variables: { service }, - }) - .then(response => response.data); - } - - getAuthToken() { - return getAuthToken(); - } - - publishService() { - const authToken = this.getAuthToken(); - const publishFlag = selectServicePublish(this.serverless.service); - if (!authToken || !publishFlag) { - // NOTE publishService is an opt-in feature and no warning is needed - return BbPromise.resolve(); - } - - this.serverless.cli.log('Publish service to Serverless Platform...'); - - const clientWithAuth = createApolloClient(config.GRAPHQL_ENDPOINT_URL, authToken); - - const region = this.provider.getRegion(); - - return this.provider.getAccountInfo().then(res => - fetchEndpoint(this.provider).then(endpoint => { - const funcs = this.serverless.service.getAllFunctions().map(key => { - const arnName = functionInfoUtils.aws.getArnName(key, this.serverless); - let funcAttributes = { - name: key, - runtime: functionInfoUtils.aws.getRuntime(key, this.serverless), - memory: functionInfoUtils.aws.getMemorySize(key, this.serverless), - timeout: functionInfoUtils.aws.getTimeout(key, this.serverless), - provider: this.serverless.service.provider.name, - originId: `arn:${res.partition}:lambda:${region}:${res.accountId}:function:${arnName}`, - endpoints: functionInfoUtils.aws.getEndpoints(key, this.serverless, endpoint), - }; - if (this.serverless.service.functions[key].readme) { - funcAttributes = addReadme( - funcAttributes, - this.serverless.service.functions[key].readme - ); - } - if (this.serverless.service.functions[key].description) { - funcAttributes.description = this.serverless.service.functions[key].description; - } - return funcAttributes; + return getAccessKey(this.config.tenant).then(accessKey => { + if (!accessKey || !this.config.app || !this.config.tenant) { + return BbPromise.resolve(); + } + const data = { + name: this.serverless.service.service, + tenant: this.config.tenant, + app: this.config.app, + accessKey, + }; + return platform.archiveService(data) + .then(() => { + this.serverless.cli.log('Successfully archived your service on the Serverless Platform'); + process.exit(0); + }) + .catch(err => { + this.serverless.cli.log('Failed to archived your service on the Serverless Platform'); + throw new this.serverless.classes.Error(err.message); }); - const serviceData = { - name: this.serverless.service.service, - stage: this.serverless.processedInput.options.stage, - functions: funcs, - }; - if (this.serverless.service.serviceObject.description) { - serviceData.description = this.serverless.service.serviceObject.description; - } - if (this.serverless.service.serviceObject.license) { - serviceData.license = this.serverless.service.serviceObject.license; - } - if (this.serverless.service.serviceObject.bugs) { - serviceData.bugs = this.serverless.service.serviceObject.bugs; - } - if (this.serverless.service.serviceObject.repository) { - serviceData.repository = this.serverless.service.serviceObject.repository; - } - if (this.serverless.service.serviceObject.homepage) { - serviceData.homepage = this.serverless.service.serviceObject.homepage; - } - - // NOTE can be improved by making sure it captures multiple variations - // of readme file name e.g. readme.md, readme.txt, Readme.md - const readmePath = path.join(this.serverless.config.servicePath, 'README.md'); - const serviceDataWithReadme = addReadme(serviceData, readmePath); - - return new BbPromise((resolve, reject) => { - this.publishServiceRequest(serviceDataWithReadme, clientWithAuth) - .then(() => { - const username = jwtDecode(authToken).nickname; - const serviceName = this.serverless.service.service; - const url = `${config.PLATFORM_FRONTEND_BASE_URL}services/${username}/${serviceName}`; - console.log('Service successfully published! Your service details are available at:'); - console.log(chalk.green(url)); - resolve(); - }) - .catch(error => { - this.serverless.cli.log( - "Couldn't publish this deploy information to the Serverless Platform." - ); - reject(error); - }); - }); - }) - ); + }); } } diff --git a/lib/utils/createApolloClient.js b/lib/utils/createApolloClient.js deleted file mode 100644 index fa66b7261..000000000 --- a/lib/utils/createApolloClient.js +++ /dev/null @@ -1,24 +0,0 @@ -const apollo = require('apollo-client'); - -module.exports = (endpoint, auth0IdToken) => { - const networkInterface = apollo.createNetworkInterface({ uri: endpoint }); - - if (auth0IdToken) { - networkInterface.use([{ - applyMiddleware(req, next) { - if (!req.options.headers) { - // eslint-disable-next-line no-param-reassign - req.options.headers = {}; - } - const token = auth0IdToken; - // eslint-disable-next-line no-param-reassign - req.options.headers.authorization = token ? `Bearer ${token}` : null; - next(); - }, - }]); - } - - return new apollo.ApolloClient({ - networkInterface, - }); -}; diff --git a/lib/utils/getAccessKey.js b/lib/utils/getAccessKey.js new file mode 100644 index 000000000..9830d5ecb --- /dev/null +++ b/lib/utils/getAccessKey.js @@ -0,0 +1,39 @@ +'use strict'; + +const configUtils = require('./config'); +const { createAccessKey } = require('@serverless/platform-sdk'); +const BbPromise = require('bluebird'); + +function getAccessKey(tenant) { + if (process.env.SERVERLESS_ACCESS_KEY) { + return BbPromise.resolve(process.env.SERVERLESS_ACCESS_KEY); + } + if (!tenant) { + return BbPromise.resolve(null); + } + + const userConfig = configUtils.getConfig(); + const currentId = userConfig.userId; + const globalConfig = configUtils.getGlobalConfig(); + if (globalConfig.users && globalConfig.users[currentId] && + globalConfig.users[currentId].dashboard) { + if (globalConfig.users[currentId].dashboard.accessKey) { + return BbPromise.resolve(globalConfig.users[currentId].dashboard.accessKey); + } else if (globalConfig.users[currentId].dashboard.idToken) { + const data = { + tenant, + username: globalConfig.users[currentId].username, + idToken: globalConfig.users[currentId].dashboard.idToken, + title: 'Framework', + }; + return createAccessKey(data).then(res => res.json()).then(res => { + globalConfig.users[currentId].dashboard.accessKey = res.secretAccessKey; + configUtils.set(globalConfig); + return res.secretAccessKey; + }); + } + } + return BbPromise.resolve(null); +} + +module.exports = getAccessKey; diff --git a/lib/utils/openBrowser.js b/lib/utils/openBrowser.js deleted file mode 100644 index 553e2327f..000000000 --- a/lib/utils/openBrowser.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -/* eslint-disable no-console */ - -const opn = require('opn'); -const chalk = require('chalk'); -const isDockerContainer = require('is-docker'); - -function displayManualOpenMessage(url, err) { - // https://github.com/sindresorhus/log-symbols - console.log('---------------------------'); - const errMsg = err ? `\nError: ${err.message}` : ''; - const msg = `Unable to open browser automatically${errMsg}`; - console.log(`🙈 ${chalk.red(msg)}`); - console.log(chalk.green('Please open your browser & open the URL below to login:')); - console.log(chalk.yellow(url)); - console.log('---------------------------'); - return false; -} - -module.exports = function openBrowser(url) { - let browser = process.env.BROWSER; - if (browser === 'none' || isDockerContainer()) { - return displayManualOpenMessage(url); - } - if (process.platform === 'darwin' && browser === 'open') { - browser = undefined; - } - const options = { app: browser }; - return opn(url, options).catch(err => displayManualOpenMessage(url, err)); -}; diff --git a/lib/utils/openBrowser.test.js b/lib/utils/openBrowser.test.js deleted file mode 100644 index dfe4ea9b3..000000000 --- a/lib/utils/openBrowser.test.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -const proxyquire = require('proxyquire'); -const sinon = require('sinon'); -const expect = require('chai').expect; - -describe('#openBrowser', () => { - let openBrowser; - let opnStub; - let isDockerStub; - - beforeEach(() => { - opnStub = sinon.stub().resolves({}); - opnStub = sinon.stub().resolves({}); - isDockerStub = sinon.stub().returns(false); - - openBrowser = proxyquire('./openBrowser', { - opn: opnStub, - 'is-docker': isDockerStub, - }); - }); - - it('should open the browser with the provided url', () => { - openBrowser('http://www.example.com'); - expect(opnStub.getCall(0).args[0]).to.equal('http://www.example.com'); - }); - - it('should open the browser with the provided url', () => { - isDockerStub = sinon.stub().returns(true); - openBrowser = proxyquire('./openBrowser', { - opn: opnStub, - 'is-docker': isDockerStub, - }); - openBrowser('http://www.example.com'); - expect(opnStub.notCalled).to.equal(true); - }); -}); diff --git a/lib/utils/selectors/selectServicePublish.js b/lib/utils/selectors/selectServicePublish.js deleted file mode 100644 index 02c3fd379..000000000 --- a/lib/utils/selectors/selectServicePublish.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -const _ = require('lodash'); - -const selectServicePublish = (service) => _.get(service, 'serviceObject.publish', true); - -module.exports = selectServicePublish; diff --git a/lib/utils/selectors/selectServicePublish.test.js b/lib/utils/selectors/selectServicePublish.test.js deleted file mode 100644 index b762eaead..000000000 --- a/lib/utils/selectors/selectServicePublish.test.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict'; - -const expect = require('chai').expect; -const selectServicePublish = require('./selectServicePublish'); - -describe('#selectServicePublish()', () => { - it('should return the publish value of the service object', () => { - const service = { - serviceObject: { - publish: true, - }, - }; - - const result = selectServicePublish(service); - - expect(result).to.equal(true); - }); -}); diff --git a/package.json b/package.json index ee65de3ef..78c26aeb6 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ }, "dependencies": { "@serverless/fdk": "^0.5.1", - "apollo-client": "^1.9.2", + "@serverless/platform-sdk": "file:../platform-sdk", "archiver": "^1.1.0", "async": "^1.5.2", "aws-sdk": "^2.228.0", @@ -106,8 +106,6 @@ "get-stdin": "^5.0.1", "globby": "^6.1.0", "graceful-fs": "^4.1.11", - "graphql": "^0.10.1", - "graphql-tag": "^2.4.0", "https-proxy-agent": "^2.2.1", "is-docker": "^1.1.0", "js-yaml": "^3.6.1", @@ -118,9 +116,7 @@ "minimist": "^1.2.0", "moment": "^2.13.0", "node-fetch": "^1.6.0", - "node-forge": "^0.7.1", "object-hash": "^1.2.0", - "opn": "^5.0.0", "promise-queue": "^2.2.3", "raven": "^1.2.1", "rc": "^1.1.6", diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 000000000..2b48c8bd5 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,6 @@ +# package directories +node_modules +jspm_packages + +# Serverless directories +.serverless \ No newline at end of file diff --git a/test/handler.js b/test/handler.js new file mode 100644 index 000000000..770e6415d --- /dev/null +++ b/test/handler.js @@ -0,0 +1,16 @@ +'use strict'; + +module.exports.hello = (event, context, callback) => { + const response = { + statusCode: 200, + body: JSON.stringify({ + message: 'Go Serverless v1.0! Your function executed successfully!', + input: event, + }), + }; + + callback(null, response); + + // Use this code if you don't use the http event with the LAMBDA-PROXY integration + // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event }); +}; diff --git a/test/serverless.yml b/test/serverless.yml new file mode 100644 index 000000000..1b9b2f43a --- /dev/null +++ b/test/serverless.yml @@ -0,0 +1,18 @@ +service: eslam-serverless-dashboard-demo + +tenant: eahefnawy +app: framework + +provider: + name: aws + runtime: nodejs6.10 + +functions: + hello: + handler: handler.hello + events: + - user.created + - http: + path: test-again + method: post + cors: true