dns check complete
This commit is contained in:
		
							parent
							
								
									2819117f10
								
							
						
					
					
						commit
						2564b750e6
					
				| @ -16,16 +16,25 @@ | |||||||
| 
 | 
 | ||||||
|       <div v-if="hasAccount"> |       <div v-if="hasAccount"> | ||||||
|         <h1>Account</h1> |         <h1>Account</h1> | ||||||
|         <form v-on:submit="challengeDns()"> |         <form v-on:submit.prevent="challengeDns()"> | ||||||
|           Add a custom domain: |           Add a custom domain: | ||||||
|           <input v-model="newDomain" placeholder="example.com" type="text" required/> |           <input v-model="newDomain" placeholder="example.com" type="text" required/> | ||||||
|           <button type="submit">Next</button> |           <button type="submit">Next</button> | ||||||
|         </form> |         </form> | ||||||
|         <form v-on:submit="challengeEmail()"> |         <form v-on:submit.prevent="challengeEmail()"> | ||||||
|           Authorize another email: |           Authorize another email: | ||||||
|           <input v-model="newEmail" placeholder="jon@example.com" type="email" required/> |           <input v-model="newEmail" placeholder="jon@example.com" type="email" required/> | ||||||
|           <button type="submit">Next</button> |           <button type="submit">Next</button> | ||||||
|         </form> |         </form> | ||||||
|  |         <h3>Claims</h3> | ||||||
|  |         <ol> | ||||||
|  |           <li v-for="claim in claims"> | ||||||
|  |             <span>{{ claim.value }}</span> | ||||||
|  |             <span v-if="'dns' === claim.type">TXT _claim-challenge.{{ claim.value }}: {{ claim.challenge }}</span> | ||||||
|  |             <button v-on:click.prevent="checkDns(claim)">Check</button> | ||||||
|  |           </li> | ||||||
|  |         </ol> | ||||||
|  |         <h3>Domains</h3> | ||||||
|         <ol> |         <ol> | ||||||
|           <li v-for="domain in domains"> |           <li v-for="domain in domains"> | ||||||
|             {{ domain }} |             {{ domain }} | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | /*global Vue*/ | ||||||
| (function () { | (function () { | ||||||
|   'use strict'; |   'use strict'; | ||||||
|   var OAUTH3 = window.OAUTH3; |   var OAUTH3 = window.OAUTH3; | ||||||
| @ -5,33 +6,7 @@ | |||||||
|     host: window.location.host |     host: window.location.host | ||||||
|   , pathname: window.location.pathname.replace(/\/[^\/]*$/, '/') |   , pathname: window.location.pathname.replace(/\/[^\/]*$/, '/') | ||||||
|   }); |   }); | ||||||
|   var $ = function () { return document.querySelector.apply(document, arguments); } |   var $ = function () { return document.querySelector.apply(document, arguments); }; | ||||||
|   var vueData = { |  | ||||||
|     domains: [] |  | ||||||
|   , newDomain: null |  | ||||||
|   , newEmail: null |  | ||||||
|   , hasAccount: false |  | ||||||
|   , token: null |  | ||||||
|   }; |  | ||||||
|   var app = new Vue({ |  | ||||||
|     el: '.v-app' |  | ||||||
|   , data: vueData |  | ||||||
|   , methods: { |  | ||||||
|       challengeDns: function () { |  | ||||||
|         console.log("A new (DNS) challenger!", vueData); |  | ||||||
|       } |  | ||||||
|     , challengeEmail: function () { |  | ||||||
|         console.log("A new (Email) challenger!", vueData); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   function listStuff(data) { |  | ||||||
|     //window.alert("TODO: show authorized devices, domains, and connectivity information");
 |  | ||||||
|     vueData.hasAccount = true; |  | ||||||
|     vueData.domains = data.domains; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   var sessionStr = localStorage.getItem('session'); |   var sessionStr = localStorage.getItem('session'); | ||||||
|   var session; |   var session; | ||||||
|   if (sessionStr) { |   if (sessionStr) { | ||||||
| @ -42,6 +17,49 @@ | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   var vueData = { | ||||||
|  |     claims: [] | ||||||
|  |   , domains: [] | ||||||
|  |   , newDomain: null | ||||||
|  |   , newDomainWildcard: false | ||||||
|  |   , newEmail: null | ||||||
|  |   , hasAccount: false | ||||||
|  |   , token: null | ||||||
|  |   }; | ||||||
|  |   var app = new Vue({ | ||||||
|  |     el: '.v-app' | ||||||
|  |   , data: vueData | ||||||
|  |   , methods: { | ||||||
|  |       challengeDns: function () { | ||||||
|  |         return oauth3.request({ | ||||||
|  |           url: 'https://api.' + location.hostname + '/api/telebit.cloud/account/authorizations/new' | ||||||
|  |         , method: 'POST' | ||||||
|  |         , session: session | ||||||
|  |         , data: { type: 'dns', value: vueData.newDomain, wildcard: vueData.newDomainWildcard } | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     , checkDns: function (claim) { | ||||||
|  |         return oauth3.request({ | ||||||
|  |           url: 'https://api.' + location.hostname + '/api/telebit.cloud/account/authorizations/new/:value/:challenge' | ||||||
|  |             .replace(/:value/g, claim.value) | ||||||
|  |             .replace(/:challenge/g, claim.challenge) | ||||||
|  |         , method: 'POST' | ||||||
|  |         , session: session | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     , challengeEmail: function () { | ||||||
|  |         console.log("A new (Email) challenger!", vueData); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  |   app = null; | ||||||
|  | 
 | ||||||
|  |   function listStuff(data) { | ||||||
|  |     //window.alert("TODO: show authorized devices, domains, and connectivity information");
 | ||||||
|  |     vueData.hasAccount = true; | ||||||
|  |     vueData.domains = data.domains; | ||||||
|  |     vueData.claims = data.claims; | ||||||
|  |   } | ||||||
|   function loadAccount(session) { |   function loadAccount(session) { | ||||||
|     return oauth3.request({ |     return oauth3.request({ | ||||||
|       url: 'https://api.' + location.hostname + '/api/telebit.cloud/account' |       url: 'https://api.' + location.hostname + '/api/telebit.cloud/account' | ||||||
| @ -64,7 +82,7 @@ | |||||||
|         , method: 'POST' |         , method: 'POST' | ||||||
|         , session: session |         , session: session | ||||||
|         , body: { |         , body: { | ||||||
|             email: email |             email: vueData.newEmail | ||||||
|           } |           } | ||||||
|         }).then(function (resp) { |         }).then(function (resp) { | ||||||
|           listStuff(resp); |           listStuff(resp); | ||||||
| @ -124,7 +142,7 @@ | |||||||
|           console.log(resp.data); |           console.log(resp.data); | ||||||
| 
 | 
 | ||||||
|           localStorage.setItem('session', JSON.stringify(session)); |           localStorage.setItem('session', JSON.stringify(session)); | ||||||
|           loadAccount(session) |           loadAccount(session); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|       }); |       }); | ||||||
| @ -138,7 +156,7 @@ | |||||||
|   $('body form.js-auth-form').addEventListener('submit', onClickLogin); |   $('body form.js-auth-form').addEventListener('submit', onClickLogin); | ||||||
|   onChangeProvider('oauth3.org'); |   onChangeProvider('oauth3.org'); | ||||||
|   if (session) { |   if (session) { | ||||||
|     vueData.token = session.access_token |     vueData.token = session.access_token; | ||||||
|     loadAccount(session); |     loadAccount(session); | ||||||
|   } |   } | ||||||
| }()); | }()); | ||||||
|  | |||||||
| @ -29,7 +29,12 @@ DB._load = function () { | |||||||
|   DB._byId = {}; |   DB._byId = {}; | ||||||
|   DB._grants = {}; |   DB._grants = {}; | ||||||
|   DB._grantsMap = {}; |   DB._grantsMap = {}; | ||||||
|  |   DB._authz = {}; | ||||||
|   DB._perms.forEach(function (acc) { |   DB._perms.forEach(function (acc) { | ||||||
|  |     if ('authz' === acc.type) { | ||||||
|  |       DB._authz[acc.id] = acc; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|     if (acc.id) { |     if (acc.id) { | ||||||
|       // if account has an id
 |       // if account has an id
 | ||||||
|       DB._byId[acc.id] = acc; |       DB._byId[acc.id] = acc; | ||||||
| @ -129,6 +134,80 @@ DB.accounts.add = function (obj) { | |||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
|  | DB.authorizations = {}; | ||||||
|  | DB.authorizations.create = function (acc, claim) { | ||||||
|  |   if (!acc.id || !claim.type || !claim.value) { throw new Error("requires account id"); } | ||||||
|  |   var crypto = require('crypto'); | ||||||
|  |   var authz = DB._authz[acc.id]; | ||||||
|  |   if (!authz) { | ||||||
|  |     authz = { | ||||||
|  |       id: acc.id | ||||||
|  |     , type: 'authz' | ||||||
|  |     , claims: [] | ||||||
|  |     }; | ||||||
|  |     DB._authz[acc.id] = authz; | ||||||
|  |     DB._perms.push(authz); | ||||||
|  |   } | ||||||
|  |   // TODO check for unique type:value pairing in claims
 | ||||||
|  |   claim.challenge = crypto.randomBytes(16).toString('hex'); | ||||||
|  |   claim.createdAt = Date.now(); | ||||||
|  |   claim.verifiedAt = 0; | ||||||
|  |   authz.claims.push(claim); | ||||||
|  |   DB.save(); | ||||||
|  |   return JSON.parse(JSON.stringify(claim)); | ||||||
|  | }; | ||||||
|  | DB.authorizations.check = function (acc, claim) { | ||||||
|  |   var authz = DB._authz[acc.id]; | ||||||
|  |   var vclaim = null; | ||||||
|  |   if (!authz) { | ||||||
|  |     return vclaim; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   authz.claims.some(function (c) { | ||||||
|  |     console.log('authz.check', c); | ||||||
|  |     if (claim.challenge) { | ||||||
|  |       if (c.challenge === claim.challenge) { | ||||||
|  |         vclaim = JSON.parse(JSON.stringify(c)); | ||||||
|  |         return true; | ||||||
|  |       } | ||||||
|  |     } else if (claim.value === c.value) { | ||||||
|  |       vclaim = JSON.parse(JSON.stringify(c)); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  |   return vclaim; | ||||||
|  | }; | ||||||
|  | DB.authorizations.checkAll = function (acc) { | ||||||
|  |   var authz = DB._authz[acc.id]; | ||||||
|  |   if (!authz) { | ||||||
|  |     return []; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return authz.claims.map(function (claim) { | ||||||
|  |     return JSON.parse(JSON.stringify(claim)); | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | DB.authorizations.verify = function (acc, claim) { | ||||||
|  |   var scmp = require('scmp'); | ||||||
|  |   var authz = DB._authz[acc.id]; | ||||||
|  |   var vclaim; | ||||||
|  |   if (!authz) { return false; } | ||||||
|  | 
 | ||||||
|  |   authz.claims.some(function (c) { | ||||||
|  |     if (scmp(c.challenge, claim.challenge)) { | ||||||
|  |       vclaim = c; | ||||||
|  |       c.verifiedAt = Date.now(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   if (vclaim) { | ||||||
|  |     DB.save(); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return false; | ||||||
|  | }; | ||||||
| DB.domains = {}; | DB.domains = {}; | ||||||
| DB.domains.available = function (name) { | DB.domains.available = function (name) { | ||||||
|   return PromiseA.resolve().then(function () { |   return PromiseA.resolve().then(function () { | ||||||
| @ -154,7 +233,7 @@ DB.domains._add = function (acc, opts) { | |||||||
|     parts.shift(); |     parts.shift(); | ||||||
|     parts.pop(); |     parts.pop(); | ||||||
|     if (parts.some(function (part) { |     if (parts.some(function (part) { | ||||||
|       if (DB._byDomain[part]) { |       if (DB._byDomain[part] && DB._byDomain[part].wildcard) { | ||||||
|         pdomain = part; |         pdomain = part; | ||||||
|         return true; |         return true; | ||||||
|       } |       } | ||||||
| @ -175,6 +254,7 @@ DB.domains._add = function (acc, opts) { | |||||||
|     , domain: domain |     , domain: domain | ||||||
|     }; |     }; | ||||||
|     acc.domains.push(domain); |     acc.domains.push(domain); | ||||||
|  |     DB.save(); | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| DB.ports = {}; | DB.ports = {}; | ||||||
|  | |||||||
| @ -19,6 +19,15 @@ var requestAsync = util.promisify(require('@coolaj86/urequest')); | |||||||
| var mkdirpAsync = util.promisify(require('mkdirp')); | 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 Claims = {}; | ||||||
|  | Claims.publicize = function publicizeClaim(claim) { | ||||||
|  |   if (!claim) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |   var result = { type: claim.type, value: claim.value, verifiedAt: claim.verifiedAt, createdAt: claim.createdAt }; | ||||||
|  |   if ('dns' === claim.type) { result.challenge = claim.challenge; } | ||||||
|  |   return result; | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| var _auths = module.exports._auths = {}; | var _auths = module.exports._auths = {}; | ||||||
| var Auths = {}; | var Auths = {}; | ||||||
| @ -763,6 +772,7 @@ app.get('/api/telebit.cloud/account', function (req, res) { | |||||||
|         //console.log(grants);
 |         //console.log(grants);
 | ||||||
|         var domainsMap = {}; |         var domainsMap = {}; | ||||||
|         var portsMap = {}; |         var portsMap = {}; | ||||||
|  |         var claimsMap = {}; | ||||||
|         var result = JSON.parse(JSON.stringify(acc)); |         var result = JSON.parse(JSON.stringify(acc)); | ||||||
|         result.domains.length = 0; |         result.domains.length = 0; | ||||||
|         result.ports.length = 0; |         result.ports.length = 0; | ||||||
| @ -775,6 +785,11 @@ app.get('/api/telebit.cloud/account', function (req, res) { | |||||||
|           account.ports.forEach(function (p) { |           account.ports.forEach(function (p) { | ||||||
|             portsMap[p.number] = p; |             portsMap[p.number] = p; | ||||||
|           }); |           }); | ||||||
|  |           DB.authorizations.checkAll({ id: account.id }).filter(function (claim) { | ||||||
|  |             return !claim.verifiedAt; | ||||||
|  |           }).forEach(function (claim) { | ||||||
|  |             claimsMap[claim.challenge] = claim; | ||||||
|  |           }); | ||||||
|         }); |         }); | ||||||
|         result.domains = Object.keys(domainsMap).map(function (k) { |         result.domains = Object.keys(domainsMap).map(function (k) { | ||||||
|           return domainsMap[k]; |           return domainsMap[k]; | ||||||
| @ -782,6 +797,9 @@ app.get('/api/telebit.cloud/account', function (req, res) { | |||||||
|         result.ports = Object.keys(portsMap).map(function (k) { |         result.ports = Object.keys(portsMap).map(function (k) { | ||||||
|           return portsMap[k]; |           return portsMap[k]; | ||||||
|         }); |         }); | ||||||
|  |         result.claims = Object.keys(claimsMap).map(function (k) { | ||||||
|  |           return Claims.publicize(claimsMap[k]); | ||||||
|  |         }); | ||||||
|         return result; |         return result; | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
| @ -821,24 +839,121 @@ app.post('/api/telebit.cloud/account', function (req, res) { | |||||||
| // Challenge Nodes / Email, Domains / DNS
 | // Challenge Nodes / Email, Domains / DNS
 | ||||||
| app.post('/api/telebit.cloud/account/authorizations/new', function (req, res) { | app.post('/api/telebit.cloud/account/authorizations/new', function (req, res) { | ||||||
|   // Send email via SMTP, confirm client's chosen pin
 |   // Send email via SMTP, confirm client's chosen pin
 | ||||||
|   res.statusCode = 500; |   var accId = Accounts._getTokenId(req.auth); | ||||||
|   res.send({ error: { code: "E_NO_IMPL", message: "not implemented" } }); |   var typ = req.body.type; | ||||||
|  |   var val = req.body.value; | ||||||
|  |   var wild = req.body.wildcard; | ||||||
|  |   var claim; | ||||||
|  | 
 | ||||||
|  |   if ('dns' === typ && /^[a-z0-9\-\.]+.[a-z]+$/i.test(val)) { | ||||||
|  |     claim = DB.authorizations.create({ id: accId }, { type: typ, value: val, wildcard: wild }); | ||||||
|  |     // MUST RETURN PUBLIC VALUES ONLY!
 | ||||||
|  |     // (challenge is public with dns because the verification is internal)
 | ||||||
|  |     res.send({ success: true, claim: claim }); | ||||||
|  |   } else if ('email' === typ) { | ||||||
|  |     //claim = DB.authorizations.create({ type: dns, claim: claim });
 | ||||||
|  |     // MUST RETURN PUBLIC VALUES ONLY!
 | ||||||
|  |     // (challenge is private with email because the verification is external)
 | ||||||
|  |     //claim.challenge = undefined;;
 | ||||||
|  |     // TODO send email
 | ||||||
|  |     res.statusCode = 501; | ||||||
|  |     res.send({ error: { code: "E_NO_IMPL", message: "authz '" + typ + "' understood but not implemented" } }); | ||||||
|  |   } else { | ||||||
|  |     res.statusCode = 501; | ||||||
|  |     res.send({ error: { code: "E_NO_IMPL", message: "unknown authz type '" + typ + "'" } }); | ||||||
|  |   } | ||||||
| }); | }); | ||||||
| app.get('/api/telebit.cloud/account/authorizations/status/:id', function (req, res) { | app.get('/api/telebit.cloud/account/authorizations/status/:value?', function (req, res) { | ||||||
|   // For client to check on status
 |   // For client to check on status
 | ||||||
|   res.statusCode = 500; |   var accId = Accounts._getTokenId(req.auth); | ||||||
|   res.send({ error: { code: "E_NO_IMPL", message: "not implemented" } }); |   var val = req.params.value; | ||||||
|  |   var result; | ||||||
|  | 
 | ||||||
|  |   if (val) { | ||||||
|  |     result = Claims.publicize(DB.authorizations.check({ id: accId }, { value: val })); | ||||||
|  |     // MUST RETURN PUBLIC VALUES ONLY!
 | ||||||
|  |     res.send({ success: true, claim: result }); | ||||||
|  |   } else { | ||||||
|  |     result = DB.authorizations.checkAll({ id: accId }).map(Claims.publicize); | ||||||
|  |     // MUST RETURN PUBLIC VALUES ONLY!
 | ||||||
|  |     res.send({ success: true, claims: result }); | ||||||
|  |   } | ||||||
| }); | }); | ||||||
| app.get('/api/telebit.cloud/account/authorizations/meta/:secret', function (req, res) { | app.get('/api/telebit.cloud/account/authorizations/meta/:secret', function (req, res) { | ||||||
|   // For agent to retrieve metadata
 |   // For agent to retrieve metadata
 | ||||||
|   res.statusCode = 500; |   res.statusCode = 500; | ||||||
|   res.send({ error: { code: "E_NO_IMPL", message: "not implemented" } }); |   res.send({ error: { code: "E_NO_IMPL", message: "not implemented" } }); | ||||||
| }); | }); | ||||||
| app.post('/api/telebit.cloud/account/authorizations/new/:magic/:pin', function (req, res) { | app.post('/api/telebit.cloud/account/authorizations/verify/:magic/:pin', function (req, res) { | ||||||
|   // For agent to confirm user's intent
 |   // For agent to confirm user's intent
 | ||||||
|   res.statusCode = 500; |   res.statusCode = 500; | ||||||
|   res.send({ error: { code: "E_NO_IMPL", message: "not implemented" } }); |   res.send({ error: { code: "E_NO_IMPL", message: "not implemented" } }); | ||||||
| }); | }); | ||||||
|  | app.post('/api/telebit.cloud/account/authorizations/new/:value/:challenge?', function (req, res) { | ||||||
|  |   // For agent to confirm user's intent
 | ||||||
|  |   var dns = require('dns'); | ||||||
|  |   var accId = Accounts._getTokenId(req.auth); | ||||||
|  |   var val = req.params.value; | ||||||
|  |   var ch = req.params.challenge; | ||||||
|  |   var claim = DB.authorizations.check({ id: accId }, { challenge: ch, value: val }); | ||||||
|  | 
 | ||||||
|  |   function notFound() { | ||||||
|  |     res.send({ error: { | ||||||
|  |       code: "E_PENDING" | ||||||
|  |     , message: "Did not find '" + claim.challenge + "' among records at '_claim-challenge." + claim.value + "'" | ||||||
|  |     } }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function grantDnsClaim() { | ||||||
|  |     return Accounts.getOrCreate(req).then(function (acc) { | ||||||
|  |       return DB.domains._add(acc, { domain: claim.value, wildcard: claim.wildcard }).then(function (result) { | ||||||
|  |         if (!DB.authorizations.verify({ id: accId }, claim)) { | ||||||
|  |           var err = new Error("'_claim-challenge." + claim.value + "' matched, but final verification failed"); | ||||||
|  |           err.code = "E_UNKNOWN"; | ||||||
|  |           return PromiseA.reject(err); | ||||||
|  |         } | ||||||
|  |         return result; | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function checkDns() { | ||||||
|  |     dns.resolveTxt('_claim-challenge.' + claim.value, function (err, records) { | ||||||
|  |       if (err) { | ||||||
|  |         notFound(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (!records.some(function (txts) { | ||||||
|  |         return txts.some(function (txt) { | ||||||
|  |           console.log('TXT', txt); | ||||||
|  |           return claim.challenge === txt; | ||||||
|  |         }); | ||||||
|  |       })) { | ||||||
|  |         notFound(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       grantDnsClaim().then(function () { | ||||||
|  |         res.send({ success: true }); | ||||||
|  |       }).catch(function (err) { | ||||||
|  |         res.send({ error: { code: err.code, message: err.toString(), _stack: err.stack } });  | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   console.log('claim', claim); | ||||||
|  | 
 | ||||||
|  |   if ('dns' === claim.type) { | ||||||
|  |     checkDns(); | ||||||
|  |   } else if ('email' === claim.type) { | ||||||
|  |     res.statusCode = 500; | ||||||
|  |     res.send({ error: { code: "E_NO_IMPL", message: "'" + claim.type + "' not implemented yet" } }); | ||||||
|  |   } else { | ||||||
|  |     res.statusCode = 500; | ||||||
|  |     res.send({ error: { code: "E_NO_IMPL", message: "'" + claim.type + "' not understood" } }); | ||||||
|  |   } | ||||||
|  | }); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // From Device (which knows id, but not secret)
 | // From Device (which knows id, but not secret)
 | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ | |||||||
|   "license": "SEE LICENSE IN LICENSE", |   "license": "SEE LICENSE IN LICENSE", | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "jwk-to-pem": "^2.0.0", |     "jwk-to-pem": "^2.0.0", | ||||||
|     "oauth3.js": "^1.2.5" |     "oauth3.js": "^1.2.5", | ||||||
|  |     "scmp": "^1.0.2" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user