exchange credential for profiles
This commit is contained in:
		
							parent
							
								
									81b213ec4b
								
							
						
					
					
						commit
						abaa59dab0
					
				
							
								
								
									
										75
									
								
								accounts.js
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								accounts.js
									
									
									
									
									
								
							| @ -61,19 +61,24 @@ function validateOtp(codeStore, codeId, token) { | |||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getOrCreate(store, username) { | function getOrCreate(store, iss, username) { | ||||||
|   // account => profile
 |   // account => profile
 | ||||||
|   return store.IssuerOauth3OrgAccounts.get(username).then(function (profile) { |   return store.IssuerOauth3OrgProfiles.find({ username: username }).then(function (profile) { | ||||||
|  |     profile = profile && profile[0]; | ||||||
|     if (profile) { |     if (profile) { | ||||||
|       return profile; |       return profile; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO profile should be ecdsa256 pub/privkeypair
 |     // TODO profile should be ecdsa256 pub/privkeypair
 | ||||||
|  |     var sub = makeB64UrlSafe(crypto.randomBytes(32).toString('base64')); | ||||||
|  |     var iss = req.experienceId; | ||||||
|     profile = { |     profile = { | ||||||
|       username:  username, |       id: sub + (iss && ('@' + iss) || '') | ||||||
|       accountId: makeB64UrlSafe(crypto.randomBytes(32).toString('base64')), |     , username:  username | ||||||
|  |     , sub: sub | ||||||
|  |     , iss: iss | ||||||
|     }; |     }; | ||||||
|     return store.IssuerOauth3OrgAccounts.create(username, profile).then(function () { |     return store.IssuerOauth3OrgProfiles.create(profile.id, profile).then(function () { | ||||||
|       // TODO: put sort sort of email notification to the server managers?
 |       // TODO: put sort sort of email notification to the server managers?
 | ||||||
|       return profile; |       return profile; | ||||||
|     }); |     }); | ||||||
| @ -176,7 +181,7 @@ function create(deps, app) { | |||||||
|   restful.sendOtp = function (req, res) { |   restful.sendOtp = function (req, res) { | ||||||
|     var params = req.body; |     var params = req.body; | ||||||
|     var promise = req.getSiteStore().then(function (store) { |     var promise = req.getSiteStore().then(function (store) { | ||||||
|       store.IssuerOauth3OrgProfiles = store.IssuerOauth3OrgProfiles || store.IssuerOauth3OrgAccounts; |       //store.IssuerOauth3OrgProfiles = store.IssuerOauth3OrgProfiles || store.IssuerOauth3OrgAccounts;
 | ||||||
|       return createOtp(store, params).then(function (code) { |       return createOtp(store, params).then(function (code) { | ||||||
|         var emailParams = { |         var emailParams = { | ||||||
|           to:      params.username, |           to:      params.username, | ||||||
| @ -241,7 +246,7 @@ function create(deps, app) { | |||||||
|           return restful.createToken._helper(req, res, tokenInfo); |           return restful.createToken._helper(req, res, tokenInfo); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         function createProfile(credential, profile) { |         function createProfile(credential, meta) { | ||||||
|           var bs58 = require('bs58'); |           var bs58 = require('bs58'); | ||||||
|           var EC = require('elliptic').ec; |           var EC = require('elliptic').ec; | ||||||
|           var ec = new EC('secp256k1'); |           var ec = new EC('secp256k1'); | ||||||
| @ -251,28 +256,25 @@ function create(deps, app) { | |||||||
|           //var ec = new EC('curve25519');
 |           //var ec = new EC('curve25519');
 | ||||||
|           var pub = bs58.encode(Buffer.from(key.derive(key.getPublic()).toString('hex'), 'hex')); |           var pub = bs58.encode(Buffer.from(key.derive(key.getPublic()).toString('hex'), 'hex')); | ||||||
|           var priv = bs58.encode(Buffer.from(key.priv.toString('hex'), 'hex')); |           var priv = bs58.encode(Buffer.from(key.priv.toString('hex'), 'hex')); | ||||||
|           var parts = []; |           var iss = req.experienceId; | ||||||
|  |           var id = pub + '@' + iss; | ||||||
| 
 | 
 | ||||||
|           if (!credential.sub) { |           if (!credential.sub) { | ||||||
|             return deps.Promise.reject(new Error("missing 'sub' from credential")); |             return deps.Promise.reject(new Error("missing 'sub' from credential")); | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           if (credential.sub !== profile.sub || credential.iss !== profile.iss) { |           if (credential.sub !== meta.sub || credential.iss !== meta.iss) { | ||||||
|             return deps.Promise.reject(new Error("credential 'sub' and 'iss' do not match information in profile")); |             return deps.Promise.reject(new Error("credential 'sub' and 'iss' do not match information in request body")); | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           parts.push(pub); |  | ||||||
|           if (req.experienceId) { |  | ||||||
|             parts.push(req.experienceId); |  | ||||||
|           } |  | ||||||
| 
 |  | ||||||
|           var username = parts.join('@'); |  | ||||||
|           var profile = { |           var profile = { | ||||||
|             accountId: pub // profile.sub
 |             id: id | ||||||
|  |           //  accountId: pub // profile.sub
 | ||||||
|           , sub: pub // profile.sub
 |           , sub: pub // profile.sub
 | ||||||
|           , iss: req.experienceId |           , iss: req.experienceId | ||||||
|           , prv: priv |           , prv: priv | ||||||
|           , typ: 'oauth3' |           , typ: 'profile' | ||||||
|  |           , username: id | ||||||
|           }; |           }; | ||||||
| 
 | 
 | ||||||
|           function getId(token) { |           function getId(token) { | ||||||
| @ -280,17 +282,15 @@ function create(deps, app) { | |||||||
|             if (token.iss) { |             if (token.iss) { | ||||||
|               id += '@' + token.iss; |               id += '@' + token.iss; | ||||||
|             } |             } | ||||||
|             return id || token.accountId; |             return id || token.id || token.accountId; | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           console.log('[debug] username, credential, profile:'); |           console.log('[debug] id, credential, profile:'); | ||||||
|           console.log(username); |           console.log(id); | ||||||
|           console.log(credential); |           console.log(credential); | ||||||
|           console.log(profile); |           console.log(profile); | ||||||
| 
 | 
 | ||||||
|           return deps.Promise.reject(new Error("blah blah grrr grrr")); |           return store.IssuerOauth3OrgProfiles.create(profile.id/*username*/, profile).then(function () { | ||||||
| 
 |  | ||||||
|           return store.IssuerOauth3OrgAccounts.create(username, profile).then(function () { |  | ||||||
|             var id = crypto.randomBytes(16).toString('hex'); |             var id = crypto.randomBytes(16).toString('hex'); | ||||||
|             return store.IssuerOauth3OrgCredentialsProfiles.create(id, { |             return store.IssuerOauth3OrgCredentialsProfiles.create(id, { | ||||||
|               credentialId: getId(credential) |               credentialId: getId(credential) | ||||||
| @ -308,12 +308,13 @@ function create(deps, app) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         function getProfile() { |         function getProfile() { | ||||||
|           var query = { username: 'IN ' + joins.map(function (el) { return el.profileId }).join(',') }; |           var query = { id: 'IN ' + joins.map(function (el) { return el.profileId }).join(',') }; | ||||||
|  |           //var query = { username: 'IN ' + joins.map(function (el) { return el.profileId }).join(',') };
 | ||||||
|           //var query = { accountId: 'IN ' + joins.map(function (el) { return el.profileId }).join(',') };
 |           //var query = { accountId: 'IN ' + joins.map(function (el) { return el.profileId }).join(',') };
 | ||||||
|           //var query = { accountId: joins.map(function (el) { return el.profileId })[0] };
 |           //var query = { accountId: joins.map(function (el) { return el.profileId })[0] };
 | ||||||
|           console.log('[DEBUG] query profiles:'); |           console.log('[DEBUG] query profiles:'); | ||||||
|           console.log(query); |           console.log(query); | ||||||
|           return req.Models.IssuerOauth3OrgAccounts.find(query).then(function (profiles) { |           return req.Models.IssuerOauth3OrgProfiles.find(query).then(function (profiles) { | ||||||
|             console.log('[DEBUG] Profiles:'); |             console.log('[DEBUG] Profiles:'); | ||||||
|             console.log(profiles); |             console.log(profiles); | ||||||
| 
 | 
 | ||||||
| @ -363,7 +364,7 @@ function create(deps, app) { | |||||||
|     var store; |     var store; | ||||||
|     var promise = req.getSiteStore().then(function (_store) { |     var promise = req.getSiteStore().then(function (_store) { | ||||||
|       store = _store; |       store = _store; | ||||||
|       store.IssuerOauth3OrgProfiles = store.IssuerOauth3OrgProfiles || store.IssuerOauth3OrgAccounts; |       //store.IssuerOauth3OrgProfiles = store.IssuerOauth3OrgProfiles || store.IssuerOauth3OrgAccounts;
 | ||||||
|       if (!req.body || !req.body.grant_type) { |       if (!req.body || !req.body.grant_type) { | ||||||
|         throw new OpErr("missing 'grant_type' from the body"); |         throw new OpErr("missing 'grant_type' from the body"); | ||||||
|       } |       } | ||||||
| @ -486,19 +487,20 @@ function create(deps, app) { | |||||||
|     var codeId = crypto.createHash('sha256').update(params.username_type+':'+params.username).digest('base64'); |     var codeId = crypto.createHash('sha256').update(params.username_type+':'+params.username).digest('base64'); | ||||||
|     codeId = makeB64UrlSafe(codeId); |     codeId = makeB64UrlSafe(codeId); | ||||||
|     return req.getSiteStore().then(function (store) { |     return req.getSiteStore().then(function (store) { | ||||||
|       store.IssuerOauth3OrgProfiles = store.IssuerOauth3OrgProfiles || store.IssuerOauth3OrgAccounts; |       //store.IssuerOauth3OrgProfiles = store.IssuerOauth3OrgProfiles || store.IssuerOauth3OrgAccounts;
 | ||||||
|       return validateOtp(store.IssuerOauth3OrgCodes, codeId, params.password) |       return validateOtp(store.IssuerOauth3OrgCodes, codeId, params.password) | ||||||
|       .then(function () { |       .then(function () { | ||||||
|         return getOrCreate(store, params.username); |         return getOrCreate(store, req.experienceId, params.username); | ||||||
|       }).then(function (account) { |       }).then(function (account) { | ||||||
|         var contactClaimId = crypto.createHash('sha256').update(account.accountId+':'+params.username_type+':'+params.username).digest('base64'); |         var contactClaimId = crypto.createHash('sha256').update(account.sub+':'+params.username_type+':'+params.username).digest('base64'); | ||||||
|  |         //var contactClaimId = crypto.createHash('sha256').update(account.accountId+':'+params.username_type+':'+params.username).digest('base64');
 | ||||||
|         return req.Models.IssuerOauth3OrgContactNodes.get(contactClaimId).then(function (contactClaim) { |         return req.Models.IssuerOauth3OrgContactNodes.get(contactClaimId).then(function (contactClaim) { | ||||||
|           var now = Date.now(); |           var now = Date.now(); | ||||||
|           if (!contactClaim) { contactClaim = { id: contactClaimId }; } |           if (!contactClaim) { contactClaim = { id: contactClaimId }; } | ||||||
|           if (!contactClaim.verifiedAt) { contactClaim.verifiedAt = now; } |           if (!contactClaim.verifiedAt) { contactClaim.verifiedAt = now; } | ||||||
|           contactClaim.lastVerifiedAt = now; |           contactClaim.lastVerifiedAt = now; | ||||||
| 
 | 
 | ||||||
|           console.log('contactClaim'); |           console.log('[DEBUG] contactClaim'); | ||||||
|           console.log(contactClaim); |           console.log(contactClaim); | ||||||
|           return req.Models.IssuerOauth3OrgContactNodes.upsert(contactClaim).then(function () { |           return req.Models.IssuerOauth3OrgContactNodes.upsert(contactClaim).then(function () { | ||||||
|             return { |             return { | ||||||
| @ -540,7 +542,7 @@ function create(deps, app) { | |||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   restful.getProfile = function (req, res) { |   restful.getProfile = function (req, res) { | ||||||
|     var promise = req.Models.IssuerOauth3OrgAccounts.get(req.oauth3.accountIdx).then(function (result) { |     var promise = req.Models.IssuerOauth3OrgProfiles.get(req.oauth3._IDX_ || req.oauth3.accountIdx).then(function (result) { | ||||||
|       if (!result) { result = { id: undefined }; } |       if (!result) { result = { id: undefined }; } | ||||||
| 
 | 
 | ||||||
|       result.id = undefined; |       result.id = undefined; | ||||||
| @ -551,11 +553,11 @@ function create(deps, app) { | |||||||
|     app.handlePromise(req, res, promise, '[issuer@oauth3.org] get profile'); |     app.handlePromise(req, res, promise, '[issuer@oauth3.org] get profile'); | ||||||
|   }; |   }; | ||||||
|   restful.setProfile = function (req, res) { |   restful.setProfile = function (req, res) { | ||||||
|     console.log('req.oauth3'); |     console.log('[setProfile] req.oauth3:'); | ||||||
|     console.log(req.oauth3); |     console.log(req.oauth3); | ||||||
| 
 | 
 | ||||||
|     var body = req.body; |     var body = req.body; | ||||||
|     var promise = req.Models.IssuerOauth3OrgAccounts.find({ accountId: req.oauth3.ppid }).then(function (results) { |     var promise = req.Models.IssuerOauth3OrgProfiles.find({ sub: req.oauth3.ppid, iss: req.experienceId }).then(function (results) { | ||||||
|       var result = results[0]; |       var result = results[0]; | ||||||
|       var changed = false; |       var changed = false; | ||||||
| 
 | 
 | ||||||
| @ -575,7 +577,7 @@ function create(deps, app) { | |||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       if (changed) { |       if (changed) { | ||||||
|         return req.Models.IssuerOauth3OrgAccounts.upsert(result).then(function () { console.log('update updated'); return result; }); |         return req.Models.IssuerOauth3OrgProfiles.upsert(result).then(function () { console.log('update updated'); return result; }); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       return result; |       return result; | ||||||
| @ -626,7 +628,8 @@ function create(deps, app) { | |||||||
|         throw new OpErr("code didn't have contact node and type information"); |         throw new OpErr("code didn't have contact node and type information"); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       var contactClaimId = crypto.createHash('sha256').update(req.oauth3.accountIdx+':'+code.node.type+':'+code.node.node).digest('base64'); |       // TODO this token may represent a 3rd-party credential or 1st-party profile. What should the ID be?
 | ||||||
|  |       var contactClaimId = crypto.createHash('sha256').update((req.oauth3._IDX_ || req.oauth3.accountIdx)+':'+code.node.type+':'+code.node.node).digest('base64'); | ||||||
|       return req.Models.IssuerOauth3OrgContactNodes.get(contactClaimId).then(function (contactClaim) { |       return req.Models.IssuerOauth3OrgContactNodes.get(contactClaimId).then(function (contactClaim) { | ||||||
|         var now = Date.now(); |         var now = Date.now(); | ||||||
|         if (!contactClaim) { contactClaim = { id: contactClaimId }; } |         if (!contactClaim) { contactClaim = { id: contactClaimId }; } | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								models.js
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								models.js
									
									
									
									
									
								
							| @ -18,7 +18,7 @@ module.exports = [ | |||||||
|     tablename: apiname + '_credentials', |     tablename: apiname + '_credentials', | ||||||
|     idname: 'id', |     idname: 'id', | ||||||
|     // credentialId = ppid@iss
 |     // credentialId = ppid@iss
 | ||||||
|     indices: baseFields.concat([ 'credentialId', 'sub', 'iss', 'typ' ]), // comment, recoveryCredential
 |     indices: baseFields.concat([ 'username', 'sub', 'iss', 'typ', 'salt', 'shadow' ]), // comment, recoveryCredential
 | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     tablename: apiname + '_credentials_profiles', |     tablename: apiname + '_credentials_profiles', | ||||||
| @ -26,15 +26,16 @@ module.exports = [ | |||||||
|     // credentialId = ppid@iss
 |     // credentialId = ppid@iss
 | ||||||
|     indices: baseFields.concat([ 'credentialId', 'profileId' ]), |     indices: baseFields.concat([ 'credentialId', 'profileId' ]), | ||||||
|   }, |   }, | ||||||
|   { // TODO rename to profiles
 |   { | ||||||
|     tablename: apiname + '_accounts', |     tablename: apiname + '_profiles', | ||||||
|     idname: 'username', |     idname: 'id', | ||||||
|     // make sub an ecdsa256 key
 |     // make sub an ecdsa256 key
 | ||||||
|     indices: baseFields.concat([ 'accountId', 'sub', 'iss', 'typ', 'privateKey' ]), // comment, recoveryNode
 |     indices: baseFields.concat([ 'username', 'sub', 'iss', 'typ', 'privateKey' ]), // comment, recoveryNodes
 | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|     tablename: apiname + '_contact_nodes', |     tablename: apiname + '_contact_nodes', | ||||||
|     idname: 'id', |     idname: 'id', | ||||||
|  |     // contact nodes could apply to either credential or profile?
 | ||||||
|     indices: baseFields.concat([ 'accountId', 'verifiedAt', 'lastVerifiedAt' ]), |     indices: baseFields.concat([ 'accountId', 'verifiedAt', 'lastVerifiedAt' ]), | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user