work in progress...

This commit is contained in:
Paul Rodwell 2016-03-31 05:47:41 +01:00
parent f5a4f6a525
commit 26d758f373
8 changed files with 150 additions and 57 deletions

View File

@ -2,6 +2,8 @@ module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-browserify'); grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-git-authors'); grunt.loadNpmTasks('grunt-git-authors');
grunt.loadNpmTasks('grunt-retire');
grunt.loadNpmTasks('grunt-nsp');
grunt.initConfig({ grunt.initConfig({
@ -23,9 +25,19 @@ module.exports = function (grunt) {
files: ['client/*.coffee'], files: ['client/*.coffee'],
tasks: ['build'] tasks: ['build']
} }
},
retire: {
node: ['.'],
options: {packageOnly: true}
},
nsp: {
package: grunt.file.readJSON('package.json')
} }
}); });
grunt.registerTask('check', ['nsp', 'retire']);
grunt.registerTask('build', ['browserify']); grunt.registerTask('build', ['browserify']);
grunt.registerTask('default', ['build']); grunt.registerTask('default', ['build']);

View File

@ -5,6 +5,7 @@ _**This security plug-in is currently a work in progress**_
Some major issues... Some major issues...
1. Twitter does not return an email address. 1. Twitter does not return an email address.
2. Github does not support using a dynamic callback URL - each wiki would need to be configured separately. 2. Github does not support using a dynamic callback URL
3. Google supports dynamic callback URL, but it must match one that expected. 3. Google supports dynamic callback URL, it allows multiple callback URLs
being defined and one of them being dynamically configured at runtime.
4. Facebook... 4. Facebook...

View File

@ -13,33 +13,43 @@
### ###
dialogCallback = (msg) -> update_footer = (ownerName, isAuthenticated, isOwner) ->
alert('Dialog callback: ' + msg)
update_footer = (owner, authUser) ->
# we update the owner and the login state in the footer, and # we update the owner and the login state in the footer, and
# populate the security dialog # populate the security dialog
if owner if ownerName
$('footer > #site-owner').html("Site Owned by: <span id='site-owner' style='text-transform:capitalize;'>#{owner}</span>") $('footer > #site-owner').html("Site Owned by: <span id='site-owner' style='text-transform:capitalize;'>#{ownerName}</span>")
$('footer > #security').empty() $('footer > #security').empty()
if authUser is true if isAuthenticated
$('footer > #security').append "<a href='#' id='show-security-dialog' class='footer-item' title='Sign-out'><i class='fa fa-unlock fa-lg fa-fw'></i></a>" $('footer > #security').append "<a href='#' id='logout' class='footer-item' title='Sign-out'><i class='fa fa-unlock fa-lg fa-fw'></i></a>"
$('footer > #security > #logout').click (e) ->
e.preventDefault()
myInit = {
method: 'GET'
cache: 'no-cache'
mode: 'same-origin'
credentials: 'include'
}
fetch '/logout', myInit
.then (response) ->
if response.ok
isAuthenticated = false
isOwner = false
user = ''
update_footer ownerName, isAuthenticated, isOwner
else
console.log 'logout failed: ', response
else else
$('footer > #security').append "<a href='#' id='show-security-dialog' class='footer-item' title='Sign-on'><i class='fa fa-lock fa-lg fa-fw'></i></a>" $('footer > #security').append "<a href='#' id='show-security-dialog' class='footer-item' title='Sign-on'><i class='fa fa-lock fa-lg fa-fw'></i></a>"
$('footer > #security > #show-security-dialog').click (e) ->
$('footer > #security')
.delegate '#show-security-dialog', 'click', (e) ->
e.preventDefault() e.preventDefault()
securityDialog = window.open("/auth/loginDialog", "_blank", "menubar=no, location=no, chrome=yes, centerscreen") securityDialog = window.open("/auth/loginDialog", "_blank", "menubar=no, location=no, chrome=yes, centerscreen")
securityDialog.window.focus() securityDialog.window.focus()
setup = (user) -> setup = (user) ->
if (!$("link[href='https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css']").length) if (!$("link[href='https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css']").length)
@ -47,8 +57,6 @@ setup = (user) ->
if (!$("link[href='/security/style.css']").length) if (!$("link[href='/security/style.css']").length)
$('<link rel="stylesheet" href="/security/style.css">').appendTo("head") $('<link rel="stylesheet" href="/security/style.css">').appendTo("head")
update_footer ownerName, isAuthenticated, isOwner
window.plugins.security = {setup, update_footer}
update_footer owner, authUser
window.plugins.security = {setup}

View File

@ -1,3 +1,7 @@
#show-security-dialog { #show-security-dialog, #logout{
color: gold; color: gold;
} }
#isOwner {
color: green;
}

View File

@ -1,7 +1,7 @@
{ {
"name": "wiki-security-social", "name": "wiki-security-passportjs",
"version": "0.0.1", "version": "0.0.1",
"description": "Security plugin for Federated Wiki, using passport social plugins", "description": "Security plugin for Federated Wiki, using passport.js",
"author": "Paul Rodwell <paul.rodwell@btinternet.com> (http://rodwell.me)", "author": "Paul Rodwell <paul.rodwell@btinternet.com> (http://rodwell.me)",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -13,8 +13,10 @@
"devDependencies": { "devDependencies": {
"coffeeify": "*", "coffeeify": "*",
"grunt": "0.4", "grunt": "0.4",
"grunt-browserify": "~4", "grunt-browserify": "~5",
"grunt-contrib-watch": "0.6", "grunt-contrib-watch": "~1",
"grunt-git-authors": "~3" "grunt-git-authors": "~3",
"grunt-retire": "*",
"grunt-nsp": "*"
} }
} }

View File

@ -28,18 +28,27 @@ module.exports = exports = (log, loga, argv) ->
#### Private stuff #### #### Private stuff ####
owner = '' owner = ''
ownerName = ''
User = {} User = {}
admin = argv.admin admin = argv.admin
statusDir = argv.statusDir statusDir = argv.status
idFile = argv.id console.log "statusDir: ", statusDir
ownerFile = path.join(statusDir, "owner.json")
personaIDFile = argv.id
usingPersona = false
ids = {} ids = {}
schemes = {} schemes = {}
# Mozilla Persona service closes on
personaEnd = new Date('2016-11-30')
#### Public stuff #### #### Public stuff ####
@ -47,9 +56,17 @@ module.exports = exports = (log, loga, argv) ->
# if it is return the owner. # if it is return the owner.
security.retrieveOwner = (cb) -> security.retrieveOwner = (cb) ->
fs.exists idFile, (exists) -> fs.exists personaIDFile, (exists) ->
if exists if exists
fs.readFile(idFile, (err, data) -> fs.readFile(personaIDFile, (err, data) ->
if err then return cb err
owner += data
usingPersona = true
cb())
else
fs.exists ownerFile, (exists) ->
if exists
fs.readFile(ownerFile, (err, data) ->
if err then return cb err if err then return cb err
owner += data owner += data
cb()) cb())
@ -58,11 +75,17 @@ module.exports = exports = (log, loga, argv) ->
cb() cb()
security.getOwner = getOwner = -> security.getOwner = getOwner = ->
if usingPersona
if ~owner.indexOf '@' if ~owner.indexOf '@'
ownerName = owner.substr(0, owner.indexOf('@')) ownerName = owner.substr(0, owner.indexOf('@'))
else else
ownerName = owner ownerName = owner
ownerName = ownerName.split('.').join(' ') ownerName = ownerName.split('.').join(' ')
else
if owner.name?
ownerName = ''
else
ownerName = owner.name
ownerName ownerName
security.setOwner = setOwner = (id, cb) -> security.setOwner = setOwner = (id, cb) ->
@ -70,19 +93,22 @@ module.exports = exports = (log, loga, argv) ->
if !exists if !exists
fs.writeFile(idFile, id, (err) -> fs.writeFile(idFile, id, (err) ->
if err then return cb err if err then return cb err
console.log "Claining site for #{id}" console.log "Claiming site for #{id}"
owner = # IDEA: owner = id
cb()) cb())
else else
cb() cb()
security.getUser = (req) -> security.getUser = (req) ->
if req.session.email if req.session.passport
return req.session.email if req.session.passport.user
return req.session.passport.user
else
return ''
else else
return '' return ''
security.isAuthorized = (req) -> security.isAuthorized = isAuthorized = (req) ->
if [req.session.email, ''].indexOf(owner) > -1 if [req.session.email, ''].indexOf(owner) > -1
return true return true
else else
@ -97,16 +123,7 @@ module.exports = exports = (log, loga, argv) ->
return false return false
security.login = (updateOwner) -> security.login = (updateOwner) ->
console.log "Login...."
security.logout = () -> security.logout = () ->
(req, res) -> (req, res) ->
@ -155,8 +172,13 @@ module.exports = exports = (log, loga, argv) ->
consumerSecret: ids['twitter'].consumerSecret consumerSecret: ids['twitter'].consumerSecret
callbackURL: '/auth/twitter/callback' callbackURL: '/auth/twitter/callback'
}, (accessToken, refreshToken, profile, cb) -> }, (accessToken, refreshToken, profile, cb) ->
console.log "Profile: ", profile user = {
cb(null, profile))) "provider": 'twitter',
"id": profile.id,
"username": profile.username,
"displayName": profile.displayName
}
cb(null, user)))
### ###
if argv.google_clientID? and argv.google_clientSecret? if argv.google_clientID? and argv.google_clientSecret?
@ -190,9 +212,9 @@ module.exports = exports = (log, loga, argv) ->
# Twitter # Twitter
app.get('/auth/twitter', passport.authenticate('twitter'), (req, res) -> ) app.get('/auth/twitter', passport.authenticate('twitter'), (req, res) -> )
app.get('/auth/twitter/callback', app.get('/auth/twitter/callback',
passport.authenticate('twitter', {failureRedirect: '/'}), (req, res) -> passport.authenticate('twitter', { successRedirect: '/auth/loginDone', failureRedirect: '/auth/loginDialog'}))
console.log 'twitter logged in!!!!'
res.send('twitter logged in'))
### Google ### Google
@ -212,11 +234,32 @@ module.exports = exports = (log, loga, argv) ->
"Wiki Site Owner Sign-on" "Wiki Site Owner Sign-on"
else else
"Sign-on to claim Wiki site" "Sign-on to claim Wiki site"
schemes: "<a href='/auth/twitter'><i class='fa fa-twitter'></i></a>" schemes: "<a href='/auth/twitter'><i class='fa fa-twitter fa-2x fa-fw'></i></a>"
} }
res.render(path.join(__dirname, '..', 'views', 'securityDialog.html'), info) res.render(path.join(__dirname, '..', 'views', 'securityDialog.html'), info)
app.get '/auth/loginDone', (req,res) ->
if owner
# do whatever we need to do if the site is already owned
else
# site is not owned, so we should claim it
info = {
title: if owner
"Wiki Site Owner Sign-on"
else
"Sign-on to claim Wiki site"
owner: getOwner
authMessage: "You are now logged in..."
}
res.render(path.join(__dirname, '..', 'views', 'done.html'), info)
app.get '/logout', (req, res) ->
console.log 'Logout...'
req.logout()
res.send("OK")

22
views/done.html Normal file
View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>Federated Wiki: Sign-on</title>
<link id='favicon' href='/favicon.png' rel='icon' type='image/png'>
<link rel="stylesheet" href="/security/style.css">
<script language='javascript' type='text/javascript'>
window.opener.plugins.security.update_footer("{{{owner}}}", true)
window.close()
</script>
</head>
<body>
<header>
<img src="/favicon.png">
{{title}}
</header>
<div>
{{{authMessage}}}
</div>
</body>
</html>

View File

@ -13,6 +13,7 @@
{{title}} {{title}}
</header> </header>
<div class="schemes"> <div class="schemes">
<p>Sign-on using:</p>
{{{schemes}}} {{{schemes}}}
</div> </div>
</body> </body>