handle remote push of domains
This commit is contained in:
		
							parent
							
								
									739f86f1cc
								
							
						
					
					
						commit
						7d11f15ebe
					
				| @ -20,6 +20,16 @@ var mkdirpAsync = util.promisify(require('mkdirp')); | |||||||
| var TRUSTED_ISSUERS = [ 'oauth3.org' ]; | var TRUSTED_ISSUERS = [ 'oauth3.org' ]; | ||||||
| var DB = require('./db.js'); | var DB = require('./db.js'); | ||||||
| var Devices = require('../device-tracker'); | var Devices = require('../device-tracker'); | ||||||
|  | var Server = require('../server'); | ||||||
|  | 
 | ||||||
|  | var OAUTH3 = require('oauth3.js').create({ pathname: process.cwd() }); | ||||||
|  | /* | ||||||
|  | // TODO all of the above should be replace with the official lib
 | ||||||
|  | return OAUTH3.jwk.verifyToken(req.auth.jwt).then(function (token) { | ||||||
|  | }).catch(function (err) { | ||||||
|  | }); | ||||||
|  | */ | ||||||
|  | 
 | ||||||
| var Claims = {}; | var Claims = {}; | ||||||
| Claims.publicize = function publicizeClaim(claim) { | Claims.publicize = function publicizeClaim(claim) { | ||||||
|   if (!claim) { |   if (!claim) { | ||||||
| @ -206,7 +216,7 @@ Accounts.getOrCreate = function (req) { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| function sendMail(state, auth) { | function sendMail(state, auth) { | ||||||
|   console.log('[DEBUG] ext auth', auth); |   //console.log('[DEBUG] ext auth', auth);
 | ||||||
|   /* |   /* | ||||||
|   curl -s --user 'api:YOUR_API_KEY' \ |   curl -s --user 'api:YOUR_API_KEY' \ | ||||||
|       https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages \
 |       https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages \
 | ||||||
| @ -267,9 +277,7 @@ function sendMail(state, auth) { | |||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|     // anything in the 200 range
 |     // anything in the 200 range
 | ||||||
|     if (2 === Math.floor(resp.statusCode / 100)) { |     if (2 !== Math.floor(resp.statusCode / 100)) { | ||||||
|       console.log("[DEBUG] email was sent, or so they say"); |  | ||||||
|     } else { |  | ||||||
|       console.error("[Error] email failed to send, or so they say:"); |       console.error("[Error] email failed to send, or so they say:"); | ||||||
|       console.error(resp.headers); |       console.error(resp.headers); | ||||||
|       console.error(resp.statusCode, resp.body); |       console.error(resp.statusCode, resp.body); | ||||||
| @ -402,7 +410,7 @@ function oauth3Auth(req, res, next) { | |||||||
|     , json: true |     , json: true | ||||||
|     }).then(function (resp) { |     }).then(function (resp) { | ||||||
|       var jwk = resp.body; |       var jwk = resp.body; | ||||||
|       console.log('Retrieved token\'s JWK: ', resp.body); |       //console.log('Retrieved token\'s JWK: ', resp.body);
 | ||||||
|       if (200 !== resp.statusCode || 'object' !== typeof resp.body) { |       if (200 !== resp.statusCode || 'object' !== typeof resp.body) { | ||||||
|         //headers.authorization
 |         //headers.authorization
 | ||||||
|         res.send({ |         res.send({ | ||||||
| @ -452,16 +460,9 @@ function oauth3Auth(req, res, next) { | |||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| var OAUTH3 = require('oauth3.js').create({ pathname: process.cwd() }); |  | ||||||
| /* |  | ||||||
| // TODO all of the above should be replace with the official lib
 |  | ||||||
| return OAUTH3.jwk.verifyToken(req.auth.jwt).then(function (token) { |  | ||||||
| }).catch(function (err) { |  | ||||||
| }); |  | ||||||
| */ |  | ||||||
| 
 | 
 | ||||||
| module.exports.pairRequest = function (opts) { | module.exports.pairRequest = function (opts) { | ||||||
|   console.log("It's auth'n time!"); |   //console.log("It's auth'n time!");
 | ||||||
|   var state = opts.state; |   var state = opts.state; | ||||||
|   var authReq = opts.auth; |   var authReq = opts.auth; | ||||||
|   var jwt = require('jsonwebtoken'); |   var jwt = require('jsonwebtoken'); | ||||||
| @ -635,23 +636,26 @@ module.exports.pairPin = function (opts) { | |||||||
| 
 | 
 | ||||||
| // From a WS connection
 | // From a WS connection
 | ||||||
| module.exports.authHelper = function (meta) { | module.exports.authHelper = function (meta) { | ||||||
|   console.log('[authHelper] 1'); |   //console.log('[authHelper] 1');
 | ||||||
|   var state = meta.state; |   var state = meta.state; | ||||||
|   console.log('[authHelper] 2'); |   //console.log('[authHelper] 2');
 | ||||||
|   return state.Promise.resolve().then(function () { |   return state.Promise.resolve().then(function () { | ||||||
|     console.log('[authHelper] 3'); |     //console.log('[authHelper] 3');
 | ||||||
|     var auth = meta.session; |     var auth = meta.session; | ||||||
|     console.log('[authHelper] 4', auth); |     //console.log('[authHelper] 4', auth);
 | ||||||
|     if (!auth || 'string' !== typeof auth.authz || 'object' !== typeof auth.authzData) { |     if (!auth || 'string' !== typeof auth.authz || 'object' !== typeof auth.authzData) { | ||||||
|       console.log('[authHelper] 5'); |       //console.log('[authHelper] 5');
 | ||||||
|       console.error("[SANITY FAIL] should not complete auth without authz data and access_token"); |       console.error("[SANITY FAIL] should not complete auth without authz data and access_token"); | ||||||
|       console.error(auth); |       console.error(auth); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     console.log("[authHelper] passing authzData right along", auth.authzData); |     //console.log("[authHelper] passing authzData right along", auth.authzData);
 | ||||||
|  |     // validatedTokenData
 | ||||||
|     return auth.authzData; |     return auth.authzData; | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | // Comes in from ../../index.js
 | ||||||
| // opts = { state: state, auth: auth_request OR access_token }
 | // opts = { state: state, auth: auth_request OR access_token }
 | ||||||
| module.exports.authenticate = function (opts) { | module.exports.authenticate = function (opts) { | ||||||
|   var jwt = require('jsonwebtoken'); |   var jwt = require('jsonwebtoken'); | ||||||
| @ -764,8 +768,7 @@ app.use('/api', CORS({ | |||||||
| })); | })); | ||||||
| app.use('/api', bodyParser.json()); | app.use('/api', bodyParser.json()); | ||||||
| 
 | 
 | ||||||
| app.use('/api/telebit.cloud/account', oauth3Auth); | function getAccountData(req) { | ||||||
| app.get('/api/telebit.cloud/account', function (req, res) { |  | ||||||
|   return Accounts.getOrCreate(req).then(function (acc) { |   return Accounts.getOrCreate(req).then(function (acc) { | ||||||
|     var hasEmail = acc.nodes.some(function (node) { |     var hasEmail = acc.nodes.some(function (node) { | ||||||
|       return 'email' === node.type; |       return 'email' === node.type; | ||||||
| @ -811,9 +814,10 @@ app.get('/api/telebit.cloud/account', function (req, res) { | |||||||
| 
 | 
 | ||||||
|         // TODO assign devices by public key, not domain name
 |         // TODO assign devices by public key, not domain name
 | ||||||
|         result.domains.map(function (domain) { |         result.domains.map(function (domain) { | ||||||
|           console.log("[debug] Domain", domain); |           console.log("[debug] Domain", domain.name); | ||||||
|           var devs = Devices.list(req._state.deviceLists, domain.name); |           var devs = Devices.list(req._state.deviceLists, domain.name); | ||||||
|           console.log("[debug] Devs", devs.map(function (d) { return d.socketId; })); |           console.log("[debug] Devs", devs); | ||||||
|  |           //console.log("[debug] Devs", devs.map(function (d) { return d.socketId; }));
 | ||||||
|           if (!devs.length) { return null; } |           if (!devs.length) { return null; } | ||||||
|           devs.forEach(function (dev) { |           devs.forEach(function (dev) { | ||||||
|             // eventually we should implement so that a new connection
 |             // eventually we should implement so that a new connection
 | ||||||
| @ -824,10 +828,23 @@ app.get('/api/telebit.cloud/account', function (req, res) { | |||||||
|                 id: dev.id |                 id: dev.id | ||||||
|               , socketId: dev.socketId |               , socketId: dev.socketId | ||||||
|               , active: true |               , active: true | ||||||
|               , names: [] |               , names: [domain.name] | ||||||
|  |               , ports: [] | ||||||
|  |               , hostname: dev.hostname | ||||||
|               }; |               }; | ||||||
|             } |             } | ||||||
|             devsMap[dev.socketId].names.push(domain.name); |             if (-1 === devsMap[dev.socketId].names.indexOf(domain.name)) { | ||||||
|  |               devsMap[dev.socketId].names.push(domain.name); | ||||||
|  |             } | ||||||
|  |             // copy over ports too
 | ||||||
|  |             Object.keys(dev.grants).forEach(function (k) { | ||||||
|  |               var grant = dev.grants[k]; | ||||||
|  |               grant.ports.forEach(function (p) { | ||||||
|  |                 if (-1 === devsMap[dev.socketId].ports.indexOf(p)) { | ||||||
|  |                   devsMap[dev.socketId].ports.push(p); | ||||||
|  |                 } | ||||||
|  |               }); | ||||||
|  |             }); | ||||||
|             return devsMap[dev.socketId]; |             return devsMap[dev.socketId]; | ||||||
|           }); |           }); | ||||||
|         }).filter(Boolean); |         }).filter(Boolean); | ||||||
| @ -855,7 +872,14 @@ app.get('/api/telebit.cloud/account', function (req, res) { | |||||||
|     } else { |     } else { | ||||||
|       return getAllGrants(); |       return getAllGrants(); | ||||||
|     } |     } | ||||||
|   }).then(function (result) { |   }); | ||||||
|  | } | ||||||
|  | app.use('/api/telebit.cloud/account', oauth3Auth); | ||||||
|  | app.use('/api/telebit.cloud/devices', oauth3Auth); | ||||||
|  | app.use('/api/telebit.cloud/domains', oauth3Auth); | ||||||
|  | app.use('/api/telebit.cloud/ports', oauth3Auth); | ||||||
|  | app.get('/api/telebit.cloud/account', function (req, res) { | ||||||
|  |   getAccountData(req).then(function (result) { | ||||||
|     res.send(result); |     res.send(result); | ||||||
|   }).catch(function (err) { |   }).catch(function (err) { | ||||||
|     return res.send({ |     return res.send({ | ||||||
| @ -867,6 +891,77 @@ app.get('/api/telebit.cloud/account', function (req, res) { | |||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
| }); | }); | ||||||
|  | app.post('/api/telebit.cloud/devices/:devId/:name', function (req, res) { | ||||||
|  |   var name = req.params.name; | ||||||
|  |   var devId = req.params.devId; | ||||||
|  |   return getAccountData(req).then(function (grants) { | ||||||
|  |     var err; | ||||||
|  |     var dev; | ||||||
|  | 
 | ||||||
|  |     // Test if we have permission to both the device and the domain
 | ||||||
|  |     if (!(grants.domains.some(function (d) { | ||||||
|  |       return d.name === name; | ||||||
|  |     }) && grants.devices.some(function (d) { | ||||||
|  |       if ((d.id && d.id === devId) || (d.socketId === devId)) { | ||||||
|  |         dev = d; | ||||||
|  |         return dev; | ||||||
|  |       } | ||||||
|  |     }))) { | ||||||
|  |       // Missing permission to one or the other
 | ||||||
|  |       err = new Error("You must have authorizations for both device '" + devId + "' and domain '" + name + "'... which you do not."); | ||||||
|  |       err.code = "E_PERM"; | ||||||
|  |       return PromiseA.reject(err); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     console.log("dev", dev); | ||||||
|  |     // Test if the specified device already uses the specified domain
 | ||||||
|  |     if (dev.names.some(function (n) { | ||||||
|  |       if (n === name) { return true; } | ||||||
|  |     })) { | ||||||
|  |       // Yep, already there. No mods needed.
 | ||||||
|  |       res.send({ success: true, modified: false }); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     var jti = crypto.randomBytes(12).toString('hex'); | ||||||
|  |     var domainsMap = {}; | ||||||
|  |     var portsMap = {}; | ||||||
|  |     var authzData = { | ||||||
|  |       id: jti | ||||||
|  |     , domains: [ name ] | ||||||
|  |     , ports: [] | ||||||
|  |     , aud: req._state.config.webminDomain | ||||||
|  |     , iat: Math.round(Date.now() / 1000) | ||||||
|  |       // of the client's computer
 | ||||||
|  |     , hostname: dev.hostname | ||||||
|  |     }; | ||||||
|  |     dev.names.forEach(function (name) { | ||||||
|  |       if (!domainsMap[name]) { | ||||||
|  |         domainsMap[name] = true; | ||||||
|  |         authzData.domains.push(name); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |     dev.ports.forEach(function (num) { | ||||||
|  |       if (!portsMap[num]) { | ||||||
|  |         portsMap[num] = true; | ||||||
|  |         authzData.ports.push(num); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |     var authz = jwt.sign(authzData, req._state.secret); | ||||||
|  |     authzData.jwt = authz; | ||||||
|  |     // TODO we need to force a grant
 | ||||||
|  |     Server.onAuth(req._state, Devices.bySocket(req._state.deviceLists, dev.socketId), authz, authzData, true); | ||||||
|  |     res.send({ success: true, data: authzData }); | ||||||
|  |   }).catch(function (err) { | ||||||
|  |     return res.send({ | ||||||
|  |       error: { | ||||||
|  |         code: err.code || "E_GENERIC" | ||||||
|  |       , message: err.toString() | ||||||
|  |       , _stack: err.stack | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| app.post('/api/telebit.cloud/account', function (req, res) { | app.post('/api/telebit.cloud/account', function (req, res) { | ||||||
|   return Accounts.create(req).then(function (acc) { |   return Accounts.create(req).then(function (acc) { | ||||||
|     res.send({ |     res.send({ | ||||||
| @ -968,7 +1063,7 @@ app.post('/api/telebit.cloud/account/authorizations/new/:value/:challenge?', fun | |||||||
| 
 | 
 | ||||||
|       if (!records.some(function (txts) { |       if (!records.some(function (txts) { | ||||||
|         return txts.some(function (txt) { |         return txts.some(function (txt) { | ||||||
|           console.log('TXT', txt); |           //console.log('TXT', txt);
 | ||||||
|           return claim.challenge === txt; |           return claim.challenge === txt; | ||||||
|         }); |         }); | ||||||
|       })) { |       })) { | ||||||
| @ -984,7 +1079,7 @@ app.post('/api/telebit.cloud/account/authorizations/new/:value/:challenge?', fun | |||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   console.log('claim', claim); |   //console.log('claim', claim);
 | ||||||
| 
 | 
 | ||||||
|   if ('dns' === claim.type) { |   if ('dns' === claim.type) { | ||||||
|     checkDns(); |     checkDns(); | ||||||
| @ -1043,8 +1138,8 @@ app.get('/api/telebit.cloud/pair_request/:secret', function (req, res) { | |||||||
| 
 | 
 | ||||||
| // From User (which has entered pin)
 | // From User (which has entered pin)
 | ||||||
| function pairCode(req, res) { | function pairCode(req, res) { | ||||||
|   console.log("DEBUG telebit.cloud magic"); |   //console.log("DEBUG telebit.cloud magic");
 | ||||||
|   console.log(req.body || req.params); |   //console.log(req.body || req.params);
 | ||||||
| 
 | 
 | ||||||
|   var magic; |   var magic; | ||||||
|   var pin; |   var pin; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user