mirror of
				https://git.coolaj86.com/coolaj86/telebit-relay.js.git
				synced 2025-11-04 10:22:46 +00:00 
			
		
		
		
	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 DB = require('./db.js');
 | 
			
		||||
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 = {};
 | 
			
		||||
Claims.publicize = function publicizeClaim(claim) {
 | 
			
		||||
  if (!claim) {
 | 
			
		||||
@ -206,7 +216,7 @@ Accounts.getOrCreate = function (req) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function sendMail(state, auth) {
 | 
			
		||||
  console.log('[DEBUG] ext auth', auth);
 | 
			
		||||
  //console.log('[DEBUG] ext auth', auth);
 | 
			
		||||
  /*
 | 
			
		||||
  curl -s --user 'api:YOUR_API_KEY' \
 | 
			
		||||
      https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages \
 | 
			
		||||
@ -267,9 +277,7 @@ function sendMail(state, auth) {
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    // anything in the 200 range
 | 
			
		||||
    if (2 === Math.floor(resp.statusCode / 100)) {
 | 
			
		||||
      console.log("[DEBUG] email was sent, or so they say");
 | 
			
		||||
    } else {
 | 
			
		||||
    if (2 !== Math.floor(resp.statusCode / 100)) {
 | 
			
		||||
      console.error("[Error] email failed to send, or so they say:");
 | 
			
		||||
      console.error(resp.headers);
 | 
			
		||||
      console.error(resp.statusCode, resp.body);
 | 
			
		||||
@ -402,7 +410,7 @@ function oauth3Auth(req, res, next) {
 | 
			
		||||
    , json: true
 | 
			
		||||
    }).then(function (resp) {
 | 
			
		||||
      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) {
 | 
			
		||||
        //headers.authorization
 | 
			
		||||
        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) {
 | 
			
		||||
  console.log("It's auth'n time!");
 | 
			
		||||
  //console.log("It's auth'n time!");
 | 
			
		||||
  var state = opts.state;
 | 
			
		||||
  var authReq = opts.auth;
 | 
			
		||||
  var jwt = require('jsonwebtoken');
 | 
			
		||||
@ -635,23 +636,26 @@ module.exports.pairPin = function (opts) {
 | 
			
		||||
 | 
			
		||||
// From a WS connection
 | 
			
		||||
module.exports.authHelper = function (meta) {
 | 
			
		||||
  console.log('[authHelper] 1');
 | 
			
		||||
  //console.log('[authHelper] 1');
 | 
			
		||||
  var state = meta.state;
 | 
			
		||||
  console.log('[authHelper] 2');
 | 
			
		||||
  //console.log('[authHelper] 2');
 | 
			
		||||
  return state.Promise.resolve().then(function () {
 | 
			
		||||
    console.log('[authHelper] 3');
 | 
			
		||||
    //console.log('[authHelper] 3');
 | 
			
		||||
    var auth = meta.session;
 | 
			
		||||
    console.log('[authHelper] 4', auth);
 | 
			
		||||
    //console.log('[authHelper] 4', auth);
 | 
			
		||||
    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(auth);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    console.log("[authHelper] passing authzData right along", auth.authzData);
 | 
			
		||||
    //console.log("[authHelper] passing authzData right along", auth.authzData);
 | 
			
		||||
    // validatedTokenData
 | 
			
		||||
    return auth.authzData;
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Comes in from ../../index.js
 | 
			
		||||
// opts = { state: state, auth: auth_request OR access_token }
 | 
			
		||||
module.exports.authenticate = function (opts) {
 | 
			
		||||
  var jwt = require('jsonwebtoken');
 | 
			
		||||
@ -764,8 +768,7 @@ app.use('/api', CORS({
 | 
			
		||||
}));
 | 
			
		||||
app.use('/api', bodyParser.json());
 | 
			
		||||
 | 
			
		||||
app.use('/api/telebit.cloud/account', oauth3Auth);
 | 
			
		||||
app.get('/api/telebit.cloud/account', function (req, res) {
 | 
			
		||||
function getAccountData(req) {
 | 
			
		||||
  return Accounts.getOrCreate(req).then(function (acc) {
 | 
			
		||||
    var hasEmail = acc.nodes.some(function (node) {
 | 
			
		||||
      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
 | 
			
		||||
        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);
 | 
			
		||||
          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; }
 | 
			
		||||
          devs.forEach(function (dev) {
 | 
			
		||||
            // 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
 | 
			
		||||
              , socketId: dev.socketId
 | 
			
		||||
              , 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];
 | 
			
		||||
          });
 | 
			
		||||
        }).filter(Boolean);
 | 
			
		||||
@ -855,7 +872,14 @@ app.get('/api/telebit.cloud/account', function (req, res) {
 | 
			
		||||
    } else {
 | 
			
		||||
      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);
 | 
			
		||||
  }).catch(function (err) {
 | 
			
		||||
    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) {
 | 
			
		||||
  return Accounts.create(req).then(function (acc) {
 | 
			
		||||
    res.send({
 | 
			
		||||
@ -968,7 +1063,7 @@ app.post('/api/telebit.cloud/account/authorizations/new/:value/:challenge?', fun
 | 
			
		||||
 | 
			
		||||
      if (!records.some(function (txts) {
 | 
			
		||||
        return txts.some(function (txt) {
 | 
			
		||||
          console.log('TXT', txt);
 | 
			
		||||
          //console.log('TXT', 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) {
 | 
			
		||||
    checkDns();
 | 
			
		||||
@ -1043,8 +1138,8 @@ app.get('/api/telebit.cloud/pair_request/:secret', function (req, res) {
 | 
			
		||||
 | 
			
		||||
// From User (which has entered pin)
 | 
			
		||||
function pairCode(req, res) {
 | 
			
		||||
  console.log("DEBUG telebit.cloud magic");
 | 
			
		||||
  console.log(req.body || req.params);
 | 
			
		||||
  //console.log("DEBUG telebit.cloud magic");
 | 
			
		||||
  //console.log(req.body || req.params);
 | 
			
		||||
 | 
			
		||||
  var magic;
 | 
			
		||||
  var pin;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user