Skip to content

Commit 07fe7d1

Browse files
committed
bootstrap oauthd default plugin me
1 parent fa81c3b commit 07fe7d1

6 files changed

+251
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
bin
2+
node_modules
3+
.DS_Store

Gruntfile.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
module.exports = function(grunt) {
3+
grunt.initConfig({
4+
coffee: {
5+
default: {
6+
expand: true,
7+
cwd: __dirname,
8+
src: ['*.coffee'],
9+
dest: 'bin',
10+
ext: '.js',
11+
options: {
12+
bare: true
13+
}
14+
}
15+
}
16+
});
17+
18+
grunt.loadNpmTasks('grunt-contrib-coffee');
19+
20+
grunt.registerTask('default', ['coffee']);
21+
};

gruntConfig.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
3+
module.exports = function(gruntConf) {
4+
gruntConf.coffee['me'] = {
5+
expand: true,
6+
cwd: __dirname,
7+
src: ['*.coffee'],
8+
dest: __dirname + '/bin',
9+
ext: '.js',
10+
options: {
11+
bare: true
12+
}
13+
};
14+
15+
gruntConf.watch['me'] = {
16+
files: [
17+
__dirname + '/**/*.coffee'
18+
],
19+
tasks: ['coffee:me']
20+
};
21+
22+
return function() {
23+
24+
}
25+
}

index.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = function(env) {
2+
var plugin = require('./bin/me.js')(env);
3+
return plugin;
4+
}

me.coffee

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# OAuth daemon
2+
# Copyright (C) 2014 Webshell SAS
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU Affero General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
18+
async = require 'async'
19+
qs = require 'querystring'
20+
Url = require 'url'
21+
restify = require 'restify'
22+
request = require 'request'
23+
zlib = require 'zlib'
24+
fs = require 'fs'
25+
Stream = require 'stream'
26+
27+
module.exports = (env) ->
28+
oauth = env.engine.oauth
29+
30+
fixUrl = (ref) -> ref.replace /^([a-zA-Z\-_]+:\/)([^\/])/, '$1/$2'
31+
32+
33+
sendAbsentFeatureError = (req, res, feature) ->
34+
res.send 501, "This provider does not support the " + feature + " feature yet"
35+
36+
cors_middleware = (req, res, next) ->
37+
oauthio = req.headers.oauthio
38+
if ! oauthio
39+
return cb new @check.Error "You must provide a valid 'oauthio' http header"
40+
oauthio = qs.parse(oauthio)
41+
if ! oauthio.k
42+
return cb new @check.Error "oauthio_key", "You must provide a 'k' (key) in 'oauthio' header"
43+
44+
origin = null
45+
ref = fixUrl(req.headers['referer'] || req.headers['origin'] || "http://localhost");
46+
urlinfos = Url.parse(ref)
47+
if not urlinfos.hostname
48+
ref = origin = "http://localhost"
49+
else
50+
origin = urlinfos.protocol + '//' + urlinfos.host
51+
res.setHeader 'Access-Control-Allow-Origin', origin
52+
res.setHeader 'Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE'
53+
next()
54+
55+
fieldMap = (body, map_array, filter) ->
56+
result = {}
57+
for k of map_array
58+
field = map_array[k]
59+
if !filter || k in filter
60+
if typeof field == 'string'
61+
if field == '='
62+
result[k] = body[k]
63+
else
64+
result[k] = body[field]
65+
else if typeof field == 'function'
66+
result[k] = field(body)
67+
result.raw = if result.raw then result.raw else body
68+
return result
69+
70+
exp = {}
71+
exp.raw = ->
72+
fixUrl = (ref) -> ref.replace /^([a-zA-Z\-_]+:\/)([^\/])/, '$1/$2'
73+
74+
check = @check
75+
@server.opts new RegExp('^/auth/([a-zA-Z0-9_\\.~-]+)/me$'), (req, res, next) =>
76+
77+
origin = null
78+
ref = fixUrl(req.headers['referer'] || req.headers['origin'] || "http://localhost");
79+
urlinfos = Url.parse(ref)
80+
if not urlinfos.hostname
81+
return next new restify.InvalidHeaderError 'Missing origin or referer.'
82+
origin = urlinfos.protocol + '//' + urlinfos.host
83+
84+
res.setHeader 'Access-Control-Allow-Origin', origin
85+
res.setHeader 'Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE'
86+
if req.headers['access-control-request-headers']
87+
res.setHeader 'Access-Control-Allow-Headers', req.headers['access-control-request-headers']
88+
res.cache maxAge: 120
89+
90+
res.send 200
91+
next false
92+
93+
@server.get new RegExp('^/auth/([a-zA-Z0-9_\\.~-]+)/me$'), restify.queryParser(), cors_middleware, (req, res, next) =>
94+
cb = @server.send res, next
95+
provider = req.params[0]
96+
filter = req.query.filter
97+
filter = filter?.split ','
98+
oauthio = req.headers.oauthio
99+
if ! oauthio
100+
return cb new Error "You must provide a valid 'oauthio' http header"
101+
oauthio = qs.parse(oauthio)
102+
if ! oauthio.k
103+
return cb new Error "oauthio_key", "You must provide a 'k' (key) in 'oauthio' header"
104+
@db.providers.getMeMapping provider, (err, content) =>
105+
if !err
106+
if content.url
107+
@apiRequest {apiUrl: content.url, headers: { 'User-Agent': 'Node' } }, provider, oauthio, (err, options) =>
108+
return sendAbsentFeatureError(req, res, 'me()') if err
109+
options.json = true
110+
request options, (err, response, body) =>
111+
return sendAbsentFeatureError(req, res, 'me()') if err
112+
# parsing body and mapping values to common field names, and sending the result
113+
res.send fieldMap(body, content.fields, filter)
114+
else if content.fetch
115+
user_fetcher = {}
116+
apiRequest = @apiRequest
117+
async.eachSeries content.fetch, (item, cb) ->
118+
if typeof item == 'object'
119+
url = item.url
120+
apiRequest {apiUrl: content.url, headers: { 'User-Agent': 'Node' } }, provider, oauthio, (err, options) =>
121+
return sendAbsentFeatureError(req, res, 'me()') if err
122+
options.json = true
123+
rq = request options, (err, response, body) =>
124+
for k of item.export
125+
value = item.export[k](body)
126+
user_fetcher[k] = value
127+
cb()
128+
chunks = []
129+
rq.on 'response', (rs) ->
130+
rs.on 'data', (chunk) ->
131+
chunks.push chunk
132+
rs.on 'end', ->
133+
buffer = Buffer.concat chunks
134+
if rs.headers['content-encoding'] == 'gzip'
135+
zlib.gunzip buffer, (err, decoded) ->
136+
res.send 500, err if err
137+
body = JSON.parse decoded.toString()
138+
for k of item.export
139+
value = item.export[k](body)
140+
user_fetcher[k] = value
141+
cb()
142+
else
143+
body = JSON.parse buffer.toString()
144+
for k of item.export
145+
value = item.export[k](body)
146+
user_fetcher[k] = value
147+
cb()
148+
if typeof item == 'function'
149+
url = item(user_fetcher)
150+
apiRequest {apiUrl: url, headers: { 'User-Agent': 'Node' } }, provider, oauthio, (err, options) =>
151+
return sendAbsentFeatureError(req, res, 'me()') if err
152+
options.json = true
153+
154+
options.headers['accept-encoding'] = undefined
155+
rq = request options
156+
chunks = []
157+
rq.on 'response', (rs) ->
158+
rs.on 'data', (chunk) ->
159+
chunks.push chunk
160+
rs.on 'end', ->
161+
buffer = Buffer.concat chunks
162+
if rs.headers['content-encoding'] == 'gzip'
163+
zlib.gunzip buffer, (err, decoded) ->
164+
res.send 500, err if err
165+
body = JSON.parse decoded.toString()
166+
res.send fieldMap(body, content.fields, filter)
167+
else
168+
body = JSON.parse buffer.toString()
169+
res.send fieldMap(body, content.fields, filter)
170+
171+
172+
, ->
173+
else
174+
return sendAbsentFeatureError(req, res, 'me()')
175+
else
176+
return sendAbsentFeatureError(req, res, 'me()')
177+
exp

package.json

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "me",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "Gruntfile.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"author": "",
10+
"license": "ISC",
11+
"devDependencies": {
12+
"grunt-contrib-coffee": "^0.11.1"
13+
},
14+
"dependencies": {
15+
"async": "^0.9.0",
16+
"querystring": "^0.2.0",
17+
"request": "^2.44.0",
18+
"restify": "^2.8.2",
19+
"sugar": "^1.4.1"
20+
}
21+
}

0 commit comments

Comments
 (0)