Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
ESSIF-Lab
TNO SSI Service
SSI Service Backend
Commits
e013aaec
Commit
e013aaec
authored
May 14, 2020
by
Hidde-Jan Jongsma
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add connector registration in organization service
parent
7e829cbc
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
448 additions
and
9 deletions
+448
-9
src/connectors/connectors.module.ts
src/connectors/connectors.module.ts
+1
-0
src/connectors/connectors.service.ts
src/connectors/connectors.service.ts
+9
-0
src/connectors/irma/irma.service.ts
src/connectors/irma/irma.service.ts
+1
-0
src/connectors/jolocom/jolocom-credential-type.entity.ts
src/connectors/jolocom/jolocom-credential-type.entity.ts
+33
-0
src/connectors/jolocom/jolocom-wallet.entity.ts
src/connectors/jolocom/jolocom-wallet.entity.ts
+54
-0
src/connectors/jolocom/jolocom.module.ts
src/connectors/jolocom/jolocom.module.ts
+5
-0
src/connectors/jolocom/jolocom.service.ts
src/connectors/jolocom/jolocom.service.ts
+323
-3
src/organizations/organizations.module.ts
src/organizations/organizations.module.ts
+2
-1
src/organizations/organizations.service.ts
src/organizations/organizations.service.ts
+20
-5
No files found.
src/connectors/connectors.module.ts
View file @
e013aaec
import
{
Module
}
from
'
@nestjs/common
'
;
import
{
JolocomModule
}
from
'
./jolocom/jolocom.module
'
;
import
{
IrmaModule
}
from
'
./irma/irma.module
'
;
import
{
ConnectorsService
}
from
'
./connectors.service
'
;
...
...
src/connectors/connectors.service.ts
View file @
e013aaec
...
...
@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
import
{
JolocomService
}
from
'
./jolocom/jolocom.service
'
;
import
{
IrmaService
}
from
'
./irma/irma.service
'
;
import
{
ConnectorService
}
from
'
./connector-service.interface
'
;
import
{
Organization
}
from
'
../organizations/organization.entity
'
;
@
Injectable
()
export
class
ConnectorsService
{
...
...
@@ -18,4 +19,12 @@ export class ConnectorsService {
getConnector
(
type
:
string
)
{
return
this
.
connectors
.
find
(
connector
=>
connector
.
type
===
type
);
}
async
registerOrganization
(
organization
:
Organization
)
{
await
Promise
.
all
(
this
.
connectors
.
map
(
async
connector
=>
await
connector
.
registerOrganization
(
organization
),
),
);
}
}
src/connectors/irma/irma.service.ts
View file @
e013aaec
...
...
@@ -7,6 +7,7 @@ export class IrmaService implements ConnectorService {
type
=
'
irma
'
;
async
registerOrganization
(
organization
:
Organization
)
{
// We don't need to do anything for IRMA.
return
;
}
}
src/connectors/jolocom/jolocom-credential-type.entity.ts
0 → 100644
View file @
e013aaec
import
{
BaseEntity
,
Entity
,
PrimaryGeneratedColumn
,
ManyToOne
,
Column
,
}
from
'
typeorm
'
;
import
{
JolocomWallet
}
from
'
./jolocom-wallet.entity
'
;
import
{
BaseMetadata
}
from
'
cred-types-jolocom-core/js/types
'
;
@
Entity
()
export
class
JolocomCredentialType
extends
BaseEntity
{
@
PrimaryGeneratedColumn
()
id
:
number
;
@
ManyToOne
(
()
=>
JolocomWallet
,
wallet
=>
wallet
.
credentialOffers
,
)
wallet
:
JolocomWallet
;
@
Column
({
unique
:
true
})
type
:
string
;
@
Column
()
name
:
string
;
@
Column
(
'
simple-json
'
)
context
:
BaseMetadata
[
'
context
'
];
@
Column
(
'
simple-json
'
)
claimInterface
:
BaseMetadata
[
'
claimInterface
'
];
}
src/connectors/jolocom/jolocom-wallet.entity.ts
View file @
e013aaec
import
{
BaseEntity
,
Entity
,
PrimaryGeneratedColumn
,
Column
,
OneToOne
,
JoinColumn
,
OneToMany
,
}
from
'
typeorm
'
;
import
{
randomBytes
}
from
'
crypto
'
;
import
{
Organization
}
from
'
../../organizations/organization.entity
'
;
import
{
JolocomCredentialType
}
from
'
./jolocom-credential-type.entity
'
;
const
JOLOCOM_WALLET_SEED_BYTES
=
32
;
const
JOLOCOM_WALLET_PASSWORD_BYTES
=
16
;
@
Entity
()
export
class
JolocomWallet
extends
BaseEntity
{
@
PrimaryGeneratedColumn
()
id
:
number
;
@
Column
({
update
:
false
})
encryptedSeedHex
:
string
;
@
Column
({
update
:
false
})
password
:
string
;
@
OneToOne
(()
=>
Organization
)
@
JoinColumn
()
organization
:
Organization
;
@
OneToMany
(
()
=>
JolocomCredentialType
,
credentialOffer
=>
credentialOffer
.
wallet
,
)
credentialOffers
:
JolocomCredentialType
[];
static
randomPassword
()
{
return
randomBytes
(
JOLOCOM_WALLET_PASSWORD_BYTES
).
toString
(
'
hex
'
);
}
static
randomSeed
()
{
return
randomBytes
(
JOLOCOM_WALLET_SEED_BYTES
);
}
get
encryptedSeed
():
Buffer
{
return
Buffer
.
from
(
this
.
encryptedSeedHex
,
'
hex
'
);
}
set
encryptedSeed
(
seed
:
Buffer
)
{
this
.
encryptedSeedHex
=
seed
.
toString
(
'
hex
'
);
}
}
src/connectors/jolocom/jolocom.module.ts
View file @
e013aaec
import
{
Module
}
from
'
@nestjs/common
'
;
import
{
TypeOrmModule
}
from
'
@nestjs/typeorm
'
;
import
{
JolocomService
}
from
'
./jolocom.service
'
;
import
{
JolocomWallet
}
from
'
./jolocom-wallet.entity
'
;
import
{
JolocomCredentialType
}
from
'
./jolocom-credential-type.entity
'
;
@
Module
({
imports
:
[
TypeOrmModule
.
forFeature
([
JolocomWallet
,
JolocomCredentialType
])],
providers
:
[
JolocomService
],
exports
:
[
JolocomService
],
})
...
...
src/connectors/jolocom/jolocom.service.ts
View file @
e013aaec
import
{
Injectable
}
from
'
@nestjs/common
'
;
import
{
Injectable
,
Logger
}
from
'
@nestjs/common
'
;
import
{
JolocomLib
}
from
'
jolocom-lib
'
;
import
{
JolocomRegistry
}
from
'
jolocom-lib/js/registries/jolocomRegistry
'
;
import
{
InjectRepository
}
from
'
@nestjs/typeorm
'
;
import
{
Repository
}
from
'
typeorm
'
;
import
{
ConnectorService
}
from
'
../connector-service.interface
'
;
import
{
Organization
}
from
'
src/organizations/organization.entity
'
;
import
{
Organization
}
from
'
../../organizations/organization.entity
'
;
import
{
JolocomWallet
}
from
'
./jolocom-wallet.entity
'
;
import
{
JolocomCredentialType
}
from
'
./jolocom-credential-type.entity
'
;
@
Injectable
()
export
class
JolocomService
implements
ConnectorService
{
type
=
'
jolocom
'
;
private
registry
:
JolocomRegistry
;
private
logger
:
Logger
;
constructor
(
@
InjectRepository
(
JolocomWallet
)
private
walletRepository
:
Repository
<
JolocomWallet
>
,
)
{
this
.
registry
=
JolocomLib
.
registries
.
jolocom
.
create
();
this
.
logger
=
new
Logger
(
JolocomService
.
name
);
}
/* ConnectorService methods */
async
registerOrganization
(
organization
:
Organization
)
{
return
;
const
wallet
=
await
this
.
createWalletForOrganization
(
organization
);
await
this
.
fuelWallet
(
wallet
);
await
this
.
registerWallet
(
wallet
);
}
async
createWalletForOrganization
(
organization
:
Organization
)
{
this
.
logger
.
log
(
`Creating wallet for
${
organization
.
name
}
`
);
const
seed
=
JolocomWallet
.
randomSeed
();
const
password
=
JolocomWallet
.
randomPassword
();
const
keyProvider
=
JolocomLib
.
KeyProvider
.
fromSeed
(
seed
,
password
);
const
wallet
=
new
JolocomWallet
();
wallet
.
organization
=
organization
;
wallet
.
password
=
password
;
wallet
.
encryptedSeedHex
=
keyProvider
.
encryptedSeed
;
// Already in hex format
await
this
.
walletRepository
.
save
(
wallet
);
this
.
logger
.
log
(
`Created wallet for
${
organization
.
name
}
`
);
return
wallet
;
}
async
registerWallet
(
wallet
:
JolocomWallet
)
{
this
.
logger
.
log
(
`Wallet registration started`
);
const
keyProvider
=
this
.
getKeyProvider
(
wallet
);
const
identityWallet
=
await
this
.
registry
.
create
(
keyProvider
,
wallet
.
password
,
);
this
.
logger
.
log
(
`Wallet registration successful`
);
// TODO: Maybe we shouldn't return here.
return
identityWallet
;
}
async
getIdentityWallet
(
wallet
:
JolocomWallet
)
{
const
keyProvider
=
this
.
getKeyProvider
(
wallet
);
const
identityWallet
=
await
this
.
registry
.
authenticate
(
keyProvider
,
{
derivationPath
:
JolocomLib
.
KeyTypes
.
jolocomIdentityKey
,
encryptionPass
:
wallet
.
password
,
});
return
identityWallet
;
}
async
fuelWallet
(
wallet
:
JolocomWallet
)
{
this
.
logger
.
log
(
`Wallet fueling started`
);
const
publicEthKey
=
this
.
getPublicEthKey
(
wallet
);
await
JolocomLib
.
util
.
fuelKeyWithEther
(
publicEthKey
);
this
.
logger
.
log
(
`Wallet fueling started`
);
}
getPublicEthKey
(
wallet
:
JolocomWallet
)
{
const
keyProvider
=
this
.
getKeyProvider
(
wallet
);
return
keyProvider
.
getPublicKey
({
encryptionPass
:
wallet
.
password
,
derivationPath
:
JolocomLib
.
KeyTypes
.
ethereumKey
,
});
}
getKeyProvider
(
wallet
:
JolocomWallet
)
{
return
new
JolocomLib
.
KeyProvider
(
wallet
.
encryptedSeed
);
}
/* Jolocom specific */
// public async processCredentialIssueRequest(
// request: CredentialIssueRequest,
// response: Response,
// ): Promise<void> {
// const credOffer = await this.createCredentialOfferToken(request);
// const token = credOffer.encode();
// const viewData = {
// requestId: request.requestId,
// qr: await QRCode.toDataURL(token),
// };
// console.log('Jolocom CredentialOfferToken: ', credOffer.encode());
// return response.render('jolocom/issue', viewData);
// }
// public async processCredentialVerifyRequest(
// verifyRequest: CredentialVerifyRequest,
// response: Response,
// ): Promise<void> {
// // Create Jolocom interaction token
// const credRequestToken = await this.createCredentialRequestToken(
// verifyRequest,
// );
// const jwt = credRequestToken.encode();
// // Render interaction token (qr code) to user
// const viewData = {
// requestId: verifyRequest.requestId,
// qr: await QRCode.toDataURL(jwt),
// };
// return response.render('jolocom/verify', viewData);
// }
/**
* Instantiate a Jolocom IdentityWallet
* This wallet must already be registered on Etherium
*
* @param organization the organization for which an identifity wallet is instantiated
*/
// protected async getIdentityWallet(
// organization: Organization,
// ): Promise<IdentityWallet> {
// const password = organization.walletConfigs.jolocom!.password;
// const seed = Buffer.from(organization.walletConfigs.jolocom!.seed, 'hex');
// /**
// * From Jolocom Documentation:
// * You will need to instantiate a Key Provider using the seed used for identity creation
// * We are currently working on simplifying, and optimising this part of the api
// */
// const vaultedKeyProvider = JolocomLib.KeyProvider.fromSeed(seed, password);
// const registry = JolocomLib.registries.jolocom.create();
// return await registry.authenticate(vaultedKeyProvider, {
// derivationPath: JolocomLib.KeyTypes.jolocomIdentityKey,
// encryptionPass: password,
// });
// }
// /**
// * Construct a Jolocom CredentialOffer interaction token
// *
// * @param issueRequest the credential issue request
// */
// protected async createCredentialOfferToken(
// issueRequest: CredentialIssueRequest,
// ): Promise<JSONWebToken<CredentialOfferRequest>> {
// const issuer = issueRequest.getIssuer();
// const identityWallet = await this.getIdentityWallet(issuer);
// const { credentialOffers, password } = issuer.walletConfigs.jolocom!;
// // Get the Jolocom offeredType and metadata from configured list with credential offers
// const {
// schema: { type: offeredType },
// metadata = {},
// } = credentialOffers[issueRequest.credentialType]; // Use the credential type URI as defined in the CredentialIssueRequest
// // Return a Jolocom CredentialOffert interaction token
// return await identityWallet.create.interactionTokens.request.offer(
// {
// callbackURL: SSIServiceApp.getUrl(
// `/connectors/jolocom/issue/${issueRequest.requestId}`,
// ),
// offeredCredentials: [
// {
// type: offeredType[offeredType.length - 1],
// ...metadata,
// },
// ],
// },
// password,
// );
// }
// /**
// * Construct a Jolocom CredentialReceive interaction token
// * to actual issue the credential to the user's wallet app
// *
// * @param issueRequest the credential issue request
// * @param jolocomOfferResponse the Jolocom CredentialOfferResponse that is received from the user's wallet app
// */
// public async createCredential(
// issueRequest: CredentialIssueRequest,
// jolocomOfferResponse: JSONWebToken<JWTEncodable>,
// ): Promise<JSONWebToken<JWTEncodable>> {
// const issuer = issueRequest.getIssuer(); // the organization that wants to issue a credential
// const identityWallet = await this.getIdentityWallet(issuer); // jolocom identity wallet of the issuer
// const password = issuer.walletConfigs.jolocom!.password; // password to sign credential
// const subject = jolocomOfferResponse.issuer; // the wallet app that wants to receive a credential
// const credentialType = issuer.walletConfigs.jolocom!.credentialOffers[
// issueRequest.credentialType
// ];
// // Create actual credential (with data)
// const credential = await identityWallet.create.signedCredential(
// {
// metadata: credentialType.schema,
// claim: {
// ...issueRequest.credentialData,
// },
// subject: keyIdToDid(subject),
// },
// password,
// );
// // Wrap credential in Jolocom interaction token object
// return await identityWallet.create.interactionTokens.response.issue(
// {
// signedCredentials: [credential.toJSON()],
// },
// password,
// jolocomOfferResponse,
// );
// }
// /**
// * Construct a Jolocom CredentialRequest interaction token
// *
// * @param verifyRequest the credential verify request
// */
// protected async createCredentialRequestToken(
// verifyRequest: CredentialVerifyRequest,
// ): Promise<JSONWebToken<CredentialRequest>> {
// const verifier = verifyRequest.getVerifier();
// const identityWallet = await this.getIdentityWallet(verifier);
// const password = verifier.walletConfigs.jolocom!.password;
// const credentialRequestToken = await identityWallet.create.interactionTokens.request.share(
// {
// callbackURL: SSIServiceApp.getUrl(
// `/connectors/jolocom/verify/${verifyRequest.requestId}`,
// ),
// credentialRequirements: [
// {
// type: ['Credential', verifyRequest.credentialType],
// constraints: [
// // TODO: implement check on allowed issuers
// // constraintFunctions.is(
// // "issuer",
// // "did:jolo:ed19430d6e28057194870dc9b19c1ca2ad099ff090b52350add129f1049bb65d"
// // )
// ],
// },
// ],
// },
// password,
// );
// // Save CredentialRequest because it is needed to verify a CredentialResponse token in the
// // next step. See method receiveCredential() below
// Store.set(credentialRequestToken.nonce, credentialRequestToken.encode());
// return credentialRequestToken;
// }
// public async receiveCredential(
// verifyRequest: CredentialVerifyRequest,
// token: string,
// ): Promise<any> {
// const jolocomCredentialResponse = JolocomLib.parse.interactionToken.fromJWT(
// token,
// );
// // TODO: check if this is needed here or can be done in JolocomConnector.receiveCredential() method
// if (!JolocomLib.util.validateDigestable(jolocomCredentialResponse)) {
// throw new Error('Invalid signature');
// // res.status(401).send("Invalid signature on interaction token");
// }
// const identityWallet = await this.getIdentityWallet(
// verifyRequest.getVerifier(),
// );
// // Get the CredentialShareToken (issued in previous interaction step)
// const jolocomCredentialRequestJWT: string = Store.get(
// jolocomCredentialResponse.nonce,
// );
// const jolocomCredentialRequest: JSONWebToken<CredentialRequest> = JolocomLib.parse.interactionToken.fromJWT(
// jolocomCredentialRequestJWT,
// );
// // The validate method will ensure the response contains a valid signature, is not expired,
// // lists our did in the aud (audience) section, and contains the same jti (nonce) as the request.
// // TODO: move this to route middleware
// await identityWallet.validateJWT(
// jolocomCredentialResponse,
// jolocomCredentialRequest,
// );
// const credentialResponse = jolocomCredentialResponse.interactionToken as CredentialResponse;
// // We check against the request we created in a previous step
// const validResponse = credentialResponse.satisfiesRequest(
// jolocomCredentialRequest.interactionToken,
// );
// if (!validResponse) {
// throw new Error('Incorrect credential received');
// }
// // Validate the provided credentials
// const providedCredentials = credentialResponse.suppliedCredentials;
// const signatureValidationResults = await JolocomLib.util.validateDigestables(
// providedCredentials,
// );
// if (signatureValidationResults.every(result => result === true)) {
// // The credentials can be used
// const data = providedCredentials.map(credential => credential.toJSON());
// // Handle the data in the provided credentials
// return verifyRequest.processCredentialData(data);
// } else {
// throw new Error('Not all provided credentials are valid');
// }
// }
}
src/organizations/organizations.module.ts
View file @
e013aaec
...
...
@@ -4,9 +4,10 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import
{
OrganizationsController
}
from
'
./organizations.controller
'
;
import
{
OrganizationsService
}
from
'
./organizations.service
'
;
import
{
Organization
}
from
'
./organization.entity
'
;
import
{
ConnectorsModule
}
from
'
src/connectors/connectors.module
'
;
@
Module
({
imports
:
[
TypeOrmModule
.
forFeature
([
Organization
])],
imports
:
[
TypeOrmModule
.
forFeature
([
Organization
])
,
ConnectorsModule
],
controllers
:
[
OrganizationsController
],
providers
:
[
OrganizationsService
],
})
...
...
src/organizations/organizations.service.ts
View file @
e013aaec
import
{
Injectable
}
from
'
@nestjs/common
'
;
import
{
Injectable
,
Logger
}
from
'
@nestjs/common
'
;
import
{
InjectRepository
}
from
'
@nestjs/typeorm
'
;
import
{
Repository
}
from
'
typeorm
'
;
import
{
Organization
}
from
'
./organization.entity
'
;
import
{
ConnectorsService
}
from
'
src/connectors/connectors.service
'
;
@
Injectable
()
export
class
OrganizationsService
{
logger
:
Logger
;
constructor
(
@
InjectRepository
(
Organization
)
private
organizationsRepository
:
Repository
<
Organization
>
,
)
{}
private
connectorsService
:
ConnectorsService
,
)
{
this
.
logger
=
new
Logger
(
Organization
.
name
);
}
findAll
()
{
async
findAll
()
{
return
this
.
organizationsRepository
.
find
();
}
createFromName
(
name
:
string
)
{
async
findByIdentifier
(
uuid
:
string
)
{
const
results
=
await
this
.
organizationsRepository
.
find
({
take
:
1
});
return
results
[
0
];
}
async
createFromName
(
name
:
string
)
{
this
.
logger
.
log
(
`Creating organization with name
${
name
}
`
);
const
organization
=
new
Organization
();
organization
.
name
=
name
;
organization
.
sharedSecret
=
Organization
.
randomSecret
();
return
this
.
organizationsRepository
.
save
(
organization
);
await
this
.
organizationsRepository
.
save
(
organization
);
await
this
.
connectorsService
.
registerOrganization
(
organization
);
this
.
logger
.
log
(
`Created organization (id:
${
organization
.
id
}
)`
);
return
organization
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment