Skip to content

Commit

Permalink
Auto-merge for PR #721 via VersionBot
Browse files Browse the repository at this point in the history
Inline the entire resin-cli-auth module
  • Loading branch information
resin-io-versionbot[bot] authored Nov 27, 2017
2 parents f106b95 + e4432d1 commit 41ff793
Show file tree
Hide file tree
Showing 16 changed files with 636 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
This project adheres to [Semantic Versioning](http://semver.org/).

## v6.10.2 - 2017-11-27

* Inline the entire resin-cli-auth module #721 [Tim Perry]

## v6.10.1 - 2017-11-27

* Set up TypeScript compilation, and make a small start on converting the CLI #720 [Tim Perry]
Expand Down
26 changes: 23 additions & 3 deletions gulpfile.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ path = require('path')
gulp = require('gulp')
coffee = require('gulp-coffee')
coffeelint = require('gulp-coffeelint')
inlinesource = require('gulp-inline-source')
mocha = require('gulp-mocha')
shell = require('gulp-shell')
packageJSON = require('./package.json')

Expand All @@ -10,10 +12,17 @@ OPTIONS =
coffeelint: path.join(__dirname, 'coffeelint.json')
files:
coffee: [ 'lib/**/*.coffee', 'gulpfile.coffee' ]
app: [ 'lib/**/*.coffee', '!lib/**/*.spec.coffee' ]
app: 'lib/**/*.coffee'
tests: 'tests/**/*.spec.coffee'
pages: 'lib/auth/pages/*.ejs'
directories:
build: 'build/'

gulp.task 'pages', ->
gulp.src(OPTIONS.files.pages)
.pipe(inlinesource())
.pipe(gulp.dest('build/auth/pages'))

gulp.task 'coffee', [ 'lint' ], ->
gulp.src(OPTIONS.files.app)
.pipe(coffee(bare: true, header: true))
Expand All @@ -26,5 +35,16 @@ gulp.task 'lint', ->
}))
.pipe(coffeelint.reporter())

gulp.task 'watch', [ 'coffee' ], ->
gulp.watch([ OPTIONS.files.coffee ], [ 'coffee' ])
gulp.task 'test', ->
gulp.src(OPTIONS.files.tests, read: false)
.pipe(mocha({
reporter: 'min'
}))

gulp.task 'build', [
'coffee',
'pages'
]

gulp.task 'watch', [ 'build' ], ->
gulp.watch([ OPTIONS.files.coffee ], [ 'build' ])
2 changes: 1 addition & 1 deletion lib/actions/auth.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ exports.login =
_ = require('lodash')
Promise = require('bluebird')
resin = require('resin-sdk-preconfigured')
auth = require('resin-cli-auth')
auth = require('../auth')
form = require('resin-cli-form')
patterns = require('../utils/patterns')
messages = require('../utils/messages')
Expand Down
5 changes: 2 additions & 3 deletions lib/actions/help.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ limitations under the License.
###

_ = require('lodash')
_.str = require('underscore.string')
capitano = require('capitano')
columnify = require('columnify')
messages = require('../utils/messages')
Expand All @@ -36,7 +35,7 @@ parse = (object) ->
]

indent = (text) ->
text = _.map _.str.lines(text), (line) ->
text = _.map text.split('\n'), (line) ->
return ' ' + line
return text.join('\n')

Expand Down Expand Up @@ -92,7 +91,7 @@ command = (params, options, done) ->
if command.help?
console.log("\n#{command.help}")
else if command.description?
console.log("\n#{_.str.humanize(command.description)}")
console.log("\n#{_.capitalize(command.description)}")

if not _.isEmpty(command.options)
console.log('\nOptions:\n')
Expand Down
63 changes: 63 additions & 0 deletions lib/auth/index.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
###
Copyright 2016 Resin.io
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.
###

###*
# @module auth
###

open = require('open')
resin = require('resin-sdk-preconfigured')
server = require('./server')
utils = require('./utils')

###*
# @summary Login to the Resin CLI using the web dashboard
# @function
# @public
#
# @description
# This function opens the user's default browser and points it
# to the Resin.io dashboard where the session token exchange will
# take place.
#
# Once the the token is retrieved, it's automatically persisted.
#
# @fulfil {String} - session token
# @returns {Promise}
#
# @example
# auth.login().then (sessionToken) ->
# console.log('I\'m logged in!')
# console.log("My session token is: #{sessionToken}")
###
exports.login = ->
options =
port: 8989
path: '/auth'

# Needs to be 127.0.0.1 not localhost, because the ip only is whitelisted
# from mixed content warnings (as the target of a form in the result page)
callbackUrl = "http://127.0.0.1:#{options.port}#{options.path}"
return utils.getDashboardLoginURL(callbackUrl).then (loginUrl) ->

# Leave a bit of time for the
# server to get up and runing
setTimeout ->
open(loginUrl)
, 1000

return server.awaitForToken(options)
.tap(resin.auth.loginWithToken)
21 changes: 21 additions & 0 deletions lib/auth/pages/error.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Resin CLI - Error</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="./static/style.css" inline>
</head>
<body>
<div class="center">
<img class="icon" src="./static/images/sad.png" inline>
<h1>Something went wrong</h1>
<p>You couldn't login to the Resin CLI for some reason</p>
<br>
<br>
<a href="https://forums.resin.io/" class="button danger">Get help in our forums</a>
</div>
</body>
</html>
Binary file added lib/auth/pages/static/images/happy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added lib/auth/pages/static/images/sad.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 60 additions & 0 deletions lib/auth/pages/static/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
html,
body {
height: 100%;
}

body {
text-align: center;
background-color: #fff;
color: rgb(24, 24, 24);
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
position: relative;
}

.center {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
width: 50%;
height: 50%;
}

.icon {
display: block;
width: 40px;
height: 45px;
margin: 0 auto;
margin-bottom: 15px;
}

h1 {
font-size: 3rem;
margin: 0;
margin-bottom: 12px;
}

p {
color: rgb(99, 99, 99);
font-size: 1.1rem;
margin: 0;
margin-bottom: 15px;
}

a.button {
padding: 15px 25px;
border-radius: 5px;
text-decoration: none;
}

a.button.danger {
background-color: rgb(235, 110, 111);
color: #fff;
}

a.button.normal {
background-color: rgb(252, 191, 44);
color: #fff;
}
21 changes: 21 additions & 0 deletions lib/auth/pages/success.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Resin CLI - Success</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="./static/style.css" inline>
</head>
<body>
<div class="center">
<img class="icon" src="./static/images/happy.png" inline>
<h1>Success!</h1>
<p>You successfully logged in the Resin CLI</p>
<br>
<br>
<a href="<%= dashboardUrl %>" class="button normal">Go to the dashboard</a>
</div>
</body>
</html>
101 changes: 101 additions & 0 deletions lib/auth/server.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
###
Copyright 2016 Resin.io
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')
resin = require('resin-sdk-preconfigured')
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.isTokenValid(token)
.tap (isValid) ->
if not isValid
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: resin.settings.get('dashboardUrl')

return Promise.resolve({})
Loading

0 comments on commit 41ff793

Please sign in to comment.