Skip to content
Snippets Groups Projects
Commit f0c9fe63 authored by Alexey Lunin's avatar Alexey Lunin
Browse files

Merge branch 'json-ld' into 'main'

feat: add json-ld support to vcm

See merge request !21
parents 910c3615 5c3342ad
No related branches found
No related tags found
1 merge request!21feat: add json-ld support to vcm
import React from 'react';
import JsonLdRawViewer from "./JsonLdRawViewer";
import VereignLegalParticipant from "./VereignLegalParticipant";
import VereignPrivatePerson from "./VereignPrivatePerson";
type JsonLdCredentialViewerProps = {
jsonld: any;
};
const JsonLdCredentialViewer: React.FC<JsonLdCredentialViewerProps> = ({
jsonld
}) => {
const subject = jsonld?.credentialSubject || {};
const subjectType = subject.type;
switch (subjectType) {
case "vereign:PrivatePerson":
return <VereignPrivatePerson jsonld={jsonld} />;
case "vereign:LegalParticipant":
return <VereignLegalParticipant jsonld={jsonld} />;
default:
return <JsonLdRawViewer jsonld={jsonld} />;
}
};
export default JsonLdCredentialViewer;
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
import {ColorPallet, TextTheme} from 'src/theme/theme';
type LegalParticipantProps = {
jsonld: any;
};
const JsonLdRawViewer: React.FC<LegalParticipantProps> = ({
jsonld,
}) => {
return (
<View>
<Text style={styles.header}>Raw JSON-LD:</Text>
<View style={styles.json}>
<Text style={styles.jsonValue}>
{JSON.stringify(jsonld, null, 2)}
</Text>
</View>
</View>
);
};
export default JsonLdRawViewer;
const styles = StyleSheet.create({
header: {
...TextTheme.normal,
color: ColorPallet.baseColors.black,
fontWeight: 'bold',
marginBottom: 8,
},
json: {
paddingVertical: 16,
},
jsonValue: {
...TextTheme.normal,
color: ColorPallet.baseColors.black,
},
});
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
import {ColorPallet, TextTheme} from 'src/theme/theme';
type LegalParticipantProps = {
jsonld: any;
};
const VereignLegalParticipant: React.FC<LegalParticipantProps> = ({
jsonld,
}) => {
const subject = jsonld?.credentialSubject || {};
const companyName = subject["vereign:companyName"];
const taxID = subject["vereign:taxID"];
const gleiCode = subject["vereign:gleiCode"];
const address = subject["vereign:address"] || {};
const street = address["vereign:street"];
const building = address["vereign:building"];
const city = address["vereign:city"];
const country = address["vereign:country"];
return (
<View>
<Text style={styles.header}>JSON-LD</Text>
<View style={styles.prop}>
<Text style={styles.propLabel}>CompanyName</Text>
<Text style={styles.propValue}>{companyName}</Text>
</View>
<View style={styles.prop}>
<Text style={styles.propLabel}>TaxID</Text>
<Text style={styles.propValue}>{taxID}</Text>
</View>
<View style={styles.prop}>
<Text style={styles.propLabel}>GleiCode</Text>
<Text style={styles.propValue}>{gleiCode}</Text>
</View>
<View style={styles.prop}>
<Text style={styles.propLabel}>Street</Text>
<Text style={styles.propValue}>{street}</Text>
</View>
<View style={styles.prop}>
<Text style={styles.propLabel}>Building</Text>
<Text style={styles.propValue}>{building}</Text>
</View>
<View style={styles.prop}>
<Text style={styles.propLabel}>City</Text>
<Text style={styles.propValue}>{city}</Text>
</View>
<View style={styles.prop}>
<Text style={styles.propLabel}>Country</Text>
<Text style={styles.propValue}>{country}</Text>
</View>
</View>
);
};
export default VereignLegalParticipant;
const styles = StyleSheet.create({
header: {
...TextTheme.normal,
color: ColorPallet.baseColors.black,
fontWeight: 'bold',
marginBottom: 8,
},
prop: {
flexDirection: 'row',
paddingVertical: 4,
},
propLabel: {
width: '40%',
...TextTheme.normal,
color: ColorPallet.baseColors.black,
fontWeight: 'bold',
},
propValue: {
width: '60%',
...TextTheme.normal,
color: ColorPallet.baseColors.black,
textAlign: 'right',
},
});
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
import {ColorPallet, TextTheme} from 'src/theme/theme';
type PrivatePersonProps = {
jsonld: any;
};
const VereignPrivatePerson: React.FC<PrivatePersonProps> = ({
jsonld,
}) => {
const subject = jsonld.credentialSubject || {};
const name = subject["vereign:name"];
const dateOfBirth = subject["vereign:dateOfBirth"];
const address = subject["vereign:address"] || {};
const street = address["vereign:street"];
const building = address["vereign:building"];
const city = address["vereign:city"];
const country = address["vereign:country"];
return (
<View>
<Text style={styles.header}>JSON-LD</Text>
<View style={styles.prop}>
<Text style={styles.propLabel}>Name</Text>
<Text style={styles.propValue}>{name}</Text>
</View>
<View style={styles.prop}>
<Text style={styles.propLabel}>DateOfBirth</Text>
<Text style={styles.propValue}>{dateOfBirth}</Text>
</View>
<View style={styles.prop}>
<Text style={styles.propLabel}>Street</Text>
<Text style={styles.propValue}>{street}</Text>
</View>
<View style={styles.prop}>
<Text style={styles.propLabel}>Building</Text>
<Text style={styles.propValue}>{building}</Text>
</View>
<View style={styles.prop}>
<Text style={styles.propLabel}>City</Text>
<Text style={styles.propValue}>{city}</Text>
</View>
<View style={styles.prop}>
<Text style={styles.propLabel}>Country</Text>
<Text style={styles.propValue}>{country}</Text>
</View>
</View>
);
};
export default VereignPrivatePerson;
const styles = StyleSheet.create({
header: {
...TextTheme.normal,
color: ColorPallet.baseColors.black,
fontWeight: 'bold',
marginBottom: 8,
},
prop: {
flexDirection: 'row',
paddingVertical: 4,
},
propLabel: {
width: '40%',
...TextTheme.normal,
color: ColorPallet.baseColors.black,
fontWeight: 'bold',
},
propValue: {
width: '60%',
...TextTheme.normal,
color: ColorPallet.baseColors.black,
textAlign: 'right',
},
});
...@@ -23,7 +23,7 @@ const NotificationListItem: React.FC<NotificationListItemProps> = ({ ...@@ -23,7 +23,7 @@ const NotificationListItem: React.FC<NotificationListItemProps> = ({
useEffect(() => { useEffect(() => {
(async () => { (async () => {
console.log(notification); console.log(JSON.stringify(notification, null, 2));
if (notification.proofRequest) { if (notification.proofRequest) {
setTitle(t<string>('ProofRequest.ProofRequest')); setTitle(t<string>('ProofRequest.ProofRequest'));
setBody(notification.connection?.theirLabel ?? 'Connectionless proof request'); setBody(notification.connection?.theirLabel ?? 'Connectionless proof request');
......
/**
* This is a copy of https://code.vereign.com/gaiax/ocm/ocm-engine/-/blob/main/libs/askar/src/credo/JsonLdCredentialFormatService.ts?ref_type=heads
* TODO do we need to move this code bellow and code by the link at OCM-Engine to separate project? (this files are the same)
*/
import {
JsonLdCredentialFormat,
JsonCredential,
JsonLdFormatDataCredentialDetail,
JsonLdFormatDataVerifiableCredential,
AgentContext,
CredentialFormatService,
Attachment,
AttachmentData,
AriesFrameworkError,
JsonEncoder,
JsonTransformer,
findVerificationMethodByKeyType,
DidResolverService,
ClaimFormat,
W3cCredential,
W3cCredentialService,
W3cJsonLdVerifiableCredential,
CredentialFormatSpec,
JsonLdCredentialDetail,
} from "@aries-framework/core";
import type {
CredentialFormatAcceptOfferOptions,
CredentialFormatAcceptProposalOptions,
CredentialFormatAcceptRequestOptions,
CredentialFormatAutoRespondOfferOptions,
CredentialFormatAutoRespondProposalOptions,
CredentialFormatAutoRespondRequestOptions,
CredentialFormatCreateOfferOptions,
CredentialFormatCreateOfferReturn,
CredentialFormatCreateProposalOptions,
CredentialFormatCreateProposalReturn,
CredentialFormatCreateRequestOptions,
CredentialFormatCreateReturn,
CredentialFormatProcessCredentialOptions,
CredentialFormatProcessOptions,
CredentialFormatAutoRespondCredentialOptions,
} from "@aries-framework/core";
import { areObjectsEqual } from "@aries-framework/core/build/utils";
import { W3cJsonLdCredentialService } from "@aries-framework/core/build/modules/vc/data-integrity/W3cJsonLdCredentialService";
const JSONLD_VC_DETAIL = "aries/ld-proof-vc-detail@v1.0";
const JSONLD_VC = "aries/ld-proof-vc@v1.0";
export class JsonLdCredentialFormatService
implements CredentialFormatService<JsonLdCredentialFormat>
{
public readonly formatKey = "jsonld" as const;
public readonly credentialRecordType = "w3c" as const;
/**
* Create a {@link AttachmentFormats} object dependent on the message type.
*
* @param options The object containing all the options for the proposed credential
* @returns object containing associated attachment, formats and filtersAttach elements
*
*/
public async createProposal(
agentContext: AgentContext,
{
credentialFormats,
}: CredentialFormatCreateProposalOptions<JsonLdCredentialFormat>,
): Promise<CredentialFormatCreateProposalReturn> {
const format = new CredentialFormatSpec({
format: JSONLD_VC_DETAIL,
});
const jsonLdFormat = credentialFormats.jsonld;
if (!jsonLdFormat) {
throw new AriesFrameworkError("Missing jsonld payload in createProposal");
}
// this does the validation
JsonTransformer.fromJSON(jsonLdFormat.credential, JsonLdCredentialDetail);
// jsonLdFormat is now of type JsonLdFormatDataCredentialDetail
const attachment = this.getFormatData(jsonLdFormat, format.attachmentId);
return { format, attachment };
}
/**
* Method called on reception of a propose credential message
* @param options the options needed to accept the proposal
*/
public async processProposal(
agentContext: AgentContext,
{ attachment }: CredentialFormatProcessOptions,
): Promise<void> {
const credProposalJson =
attachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
if (!credProposalJson) {
throw new AriesFrameworkError(
"Missing jsonld credential proposal data payload",
);
}
// validation is done in here
JsonTransformer.fromJSON(credProposalJson, JsonLdCredentialDetail);
}
public async acceptProposal(
agentContext: AgentContext,
{
attachmentId,
proposalAttachment,
}: CredentialFormatAcceptProposalOptions<JsonLdCredentialFormat>,
): Promise<CredentialFormatCreateOfferReturn> {
// if the offer has an attachment Id use that, otherwise the generated id of the formats object
const format = new CredentialFormatSpec({
attachmentId,
format: JSONLD_VC_DETAIL,
});
const credentialProposal =
proposalAttachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
JsonTransformer.fromJSON(credentialProposal, JsonLdCredentialDetail);
const offerData = credentialProposal;
const attachment = this.getFormatData(offerData, format.attachmentId);
return { format, attachment };
}
/**
* Create a {@link AttachmentFormats} object dependent on the message type.
*
* @param options The object containing all the options for the credential offer
* @returns object containing associated attachment, formats and offersAttach elements
*
*/
public async createOffer(
agentContext: AgentContext,
{
credentialFormats,
attachmentId,
}: CredentialFormatCreateOfferOptions<JsonLdCredentialFormat>,
): Promise<CredentialFormatCreateOfferReturn> {
// if the offer has an attachment Id use that, otherwise the generated id of the formats object
const format = new CredentialFormatSpec({
attachmentId,
format: JSONLD_VC_DETAIL,
});
const jsonLdFormat = credentialFormats?.jsonld;
if (!jsonLdFormat) {
throw new AriesFrameworkError("Missing jsonld payload in createOffer");
}
// validate
JsonTransformer.fromJSON(jsonLdFormat.credential, JsonLdCredentialDetail);
const attachment = this.getFormatData(jsonLdFormat, format.attachmentId);
return { format, attachment };
}
public async processOffer(
agentContext: AgentContext,
{ attachment }: CredentialFormatProcessOptions,
) {
const credentialOfferJson =
attachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
if (!credentialOfferJson) {
throw new AriesFrameworkError(
"Missing jsonld credential offer data payload",
);
}
JsonTransformer.fromJSON(credentialOfferJson, JsonLdCredentialDetail);
}
public async acceptOffer(
agentContext: AgentContext,
{
attachmentId,
offerAttachment,
}: CredentialFormatAcceptOfferOptions<JsonLdCredentialFormat>,
): Promise<CredentialFormatCreateReturn> {
const credentialOffer =
offerAttachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
// validate
JsonTransformer.fromJSON(credentialOffer, JsonLdCredentialDetail);
const format = new CredentialFormatSpec({
attachmentId,
format: JSONLD_VC_DETAIL,
});
const attachment = this.getFormatData(credentialOffer, format.attachmentId);
return { format, attachment };
}
/**
* Create a credential attachment format for a credential request.
*
* @param options The object containing all the options for the credential request is derived
* @returns object containing associated attachment, formats and requestAttach elements
*
*/
public async createRequest(
agentContext: AgentContext,
{
credentialFormats,
}: CredentialFormatCreateRequestOptions<JsonLdCredentialFormat>,
): Promise<CredentialFormatCreateReturn> {
const jsonLdFormat = credentialFormats?.jsonld;
const format = new CredentialFormatSpec({
format: JSONLD_VC_DETAIL,
});
if (!jsonLdFormat) {
throw new AriesFrameworkError("Missing jsonld payload in createRequest");
}
// this does the validation
JsonTransformer.fromJSON(jsonLdFormat.credential, JsonLdCredentialDetail);
const attachment = this.getFormatData(jsonLdFormat, format.attachmentId);
return { format, attachment };
}
public async processRequest(
agentContext: AgentContext,
{ attachment }: CredentialFormatProcessOptions,
): Promise<void> {
const requestJson =
attachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
if (!requestJson) {
throw new AriesFrameworkError(
"Missing jsonld credential request data payload",
);
}
// validate
JsonTransformer.fromJSON(requestJson, JsonLdCredentialDetail);
}
public async acceptRequest(
agentContext: AgentContext,
{
credentialFormats,
attachmentId,
requestAttachment,
}: CredentialFormatAcceptRequestOptions<JsonLdCredentialFormat>,
): Promise<CredentialFormatCreateReturn> {
const w3cJsonLdCredentialService = agentContext.dependencyManager.resolve(
W3cJsonLdCredentialService,
);
// sign credential here. credential to be signed is received as the request attachment
// (attachment in the request message from holder to issuer)
const credentialRequest =
requestAttachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
const verificationMethod =
credentialFormats?.jsonld?.verificationMethod ??
(await this.deriveVerificationMethod(
agentContext,
credentialRequest.credential,
credentialRequest,
));
if (!verificationMethod) {
throw new AriesFrameworkError(
"Missing verification method in credential data",
);
}
const format = new CredentialFormatSpec({
attachmentId,
format: JSONLD_VC,
});
const options = credentialRequest.options;
// Get a list of fields found in the options that are not supported at the moment
const unsupportedFields = [
"challenge",
"domain",
"credentialStatus",
"created",
] as const;
const foundFields = unsupportedFields.filter(
(field) => options[field] !== undefined,
);
if (foundFields.length > 0) {
throw new AriesFrameworkError(
`Some fields are not currently supported in credential options: ${foundFields.join(
", ",
)}`,
);
}
const credential = JsonTransformer.fromJSON(
credentialRequest.credential,
W3cCredential,
);
const verifiableCredential =
await w3cJsonLdCredentialService.signCredential(agentContext, {
format: ClaimFormat.LdpVc,
credential,
proofType: credentialRequest.options.proofType,
verificationMethod: verificationMethod,
});
const attachment = this.getFormatData(
JsonTransformer.toJSON(verifiableCredential),
format.attachmentId,
);
return { format, attachment };
}
/**
* Derive a verification method using the issuer from the given verifiable credential
* @param credentialAsJson the verifiable credential we want to sign
* @return the verification method derived from this credential and its associated issuer did, keys etc.
*/
private async deriveVerificationMethod(
agentContext: AgentContext,
credentialAsJson: JsonCredential,
credentialRequest: JsonLdFormatDataCredentialDetail,
): Promise<string> {
const didResolver =
agentContext.dependencyManager.resolve(DidResolverService);
const w3cJsonLdCredentialService = agentContext.dependencyManager.resolve(
W3cJsonLdCredentialService,
);
const credential = JsonTransformer.fromJSON(
credentialAsJson,
W3cCredential,
);
// extract issuer from vc (can be string or Issuer)
let issuerDid = credential.issuer;
if (typeof issuerDid !== "string") {
issuerDid = issuerDid.id;
}
// this will throw an error if the issuer did is invalid
const issuerDidDocument = await didResolver.resolveDidDocument(
agentContext,
issuerDid,
);
// find first key which matches proof type
const proofType = credentialRequest.options.proofType;
// actually gets the key type(s)
const keyType =
w3cJsonLdCredentialService.getVerificationMethodTypesByProofType(
proofType,
);
if (!keyType || keyType.length === 0) {
throw new AriesFrameworkError(
`No Key Type found for proofType ${proofType}`,
);
}
const verificationMethod = await findVerificationMethodByKeyType(
keyType[0],
issuerDidDocument,
);
if (!verificationMethod) {
throw new AriesFrameworkError(
`Missing verification method for key type ${keyType}`,
);
}
return verificationMethod.id;
}
/**
* Processes an incoming credential - retrieve metadata, retrieve payload and store it in the Indy wallet
* @param options the issue credential message wrapped inside this object
* @param credentialRecord the credential exchange record for this credential
*/
public async processCredential(
agentContext: AgentContext,
{
credentialRecord,
attachment,
requestAttachment,
}: CredentialFormatProcessCredentialOptions,
): Promise<void> {
const w3cCredentialService =
agentContext.dependencyManager.resolve(W3cCredentialService);
const credentialAsJson = attachment.getDataAsJson();
const credential = JsonTransformer.fromJSON(
credentialAsJson,
W3cJsonLdVerifiableCredential,
);
const requestAsJson =
requestAttachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
// Verify the credential request matches the credential
this.verifyReceivedCredentialMatchesRequest(credential, requestAsJson);
// verify signatures of the credential
const result = await w3cCredentialService.verifyCredential(agentContext, {
credential,
});
if (result && !result.isValid) {
throw new AriesFrameworkError(
`Failed to validate credential, error = ${result.error}`,
);
}
const verifiableCredential = await w3cCredentialService.storeCredential(
agentContext,
{
credential,
},
);
credentialRecord.credentials.push({
credentialRecordType: this.credentialRecordType,
credentialRecordId: verifiableCredential.id,
});
}
private verifyReceivedCredentialMatchesRequest(
credential: W3cJsonLdVerifiableCredential,
request: JsonLdFormatDataCredentialDetail,
): void {
const jsonCredential = JsonTransformer.toJSON(credential);
delete jsonCredential["proof"];
const credentialProof = Array.isArray(credential.proof)
? credential.proof[credential.proof.length - 1]
: credential.proof;
if (
request.options.created &&
credentialProof.created !== request.options.created
) {
throw new AriesFrameworkError(
"Received credential proof created does not match created from credential request",
);
}
if (credentialProof.domain !== request.options.domain) {
throw new AriesFrameworkError(
"Received credential proof domain does not match domain from credential request",
);
}
if (credentialProof.challenge !== request.options.challenge) {
throw new AriesFrameworkError(
"Received credential proof challenge does not match challenge from credential request",
);
}
if (credentialProof.type !== request.options.proofType) {
throw new AriesFrameworkError(
"Received credential proof type does not match proof type from credential request",
);
}
if (credentialProof.proofPurpose !== request.options.proofPurpose) {
throw new AriesFrameworkError(
"Received credential proof purpose does not match proof purpose from credential request",
);
}
// Check whether the received credential (minus the proof) matches the credential request
const requestJsonCredential = JsonTransformer.toJSON(request.credential);
delete requestJsonCredential["proof"];
if (!areObjectsEqual(jsonCredential, requestJsonCredential)) {
throw new AriesFrameworkError(
"Received credential does not match credential request",
);
}
// TODO: add check for the credentialStatus once this is supported in Credo
}
public supportsFormat(format: string): boolean {
const supportedFormats = [JSONLD_VC_DETAIL, JSONLD_VC];
return supportedFormats.includes(format);
}
public async deleteCredentialById(): Promise<void> {
throw new Error("Not implemented.");
}
public areCredentialsEqual = (
message1: Attachment,
message2: Attachment,
): boolean => {
const obj1 = message1.getDataAsJson();
const obj2 = message2.getDataAsJson();
return areObjectsEqual(obj1, obj2);
};
public async shouldAutoRespondToProposal(
agentContext: AgentContext,
{
offerAttachment,
proposalAttachment,
}: CredentialFormatAutoRespondProposalOptions,
) {
return this.areCredentialsEqual(proposalAttachment, offerAttachment);
}
public async shouldAutoRespondToOffer(
agentContext: AgentContext,
{
offerAttachment,
proposalAttachment,
}: CredentialFormatAutoRespondOfferOptions,
) {
return this.areCredentialsEqual(proposalAttachment, offerAttachment);
}
public async shouldAutoRespondToRequest(
agentContext: AgentContext,
{
offerAttachment,
requestAttachment,
}: CredentialFormatAutoRespondRequestOptions,
) {
return this.areCredentialsEqual(offerAttachment, requestAttachment);
}
public async shouldAutoRespondToCredential(
agentContext: AgentContext,
{
requestAttachment,
credentialAttachment,
}: CredentialFormatAutoRespondCredentialOptions,
) {
const credentialJson =
credentialAttachment.getDataAsJson<JsonLdFormatDataVerifiableCredential>();
const w3cCredential = JsonTransformer.fromJSON(
credentialJson,
W3cJsonLdVerifiableCredential,
);
const request =
requestAttachment.getDataAsJson<JsonLdFormatDataCredentialDetail>();
try {
// This check is also done in the processCredential method, but we do it here as well
// to be certain we don't skip the check
this.verifyReceivedCredentialMatchesRequest(w3cCredential, request);
return true;
} catch (error) {
return false;
}
}
/**
* Returns an object of type {@link Attachment} for use in credential exchange messages.
* It looks up the correct format identifier and encodes the data as a base64 attachment.
*
* @param data The data to include in the attach object
* @param id the attach id from the formats component of the message
*/
private getFormatData(data: unknown, id: string): Attachment {
const attachment = new Attachment({
id,
mimeType: "application/json",
data: new AttachmentData({
base64: JsonEncoder.toBase64(data),
}),
});
return attachment;
}
}
import {makeAutoObservable} from "mobx"; import {makeAutoObservable} from "mobx";
import rootStore from "src/store/rootStore"; import rootStore from "src/store/rootStore";
import {CredentialState, ProofState} from "@aries-framework/core"; import {CredentialState, GetCredentialFormatDataReturn, ProofState} from "@aries-framework/core";
import {RecordHistory} from "src/type/record"; import {RecordHistory} from "src/type/record";
import { import {
CredentialExchangeRecord CredentialExchangeRecord
...@@ -13,6 +13,7 @@ class CredentialDetailsStore { ...@@ -13,6 +13,7 @@ class CredentialDetailsStore {
public loading = true; public loading = true;
public credentialId: string; public credentialId: string;
private _credential: CredentialExchangeRecord | null = null; private _credential: CredentialExchangeRecord | null = null;
public credentialFormatData: GetCredentialFormatDataReturn | null = null;
public get credential(): CredentialExchangeRecord { public get credential(): CredentialExchangeRecord {
return this._credential as CredentialExchangeRecord; return this._credential as CredentialExchangeRecord;
} }
...@@ -28,6 +29,7 @@ class CredentialDetailsStore { ...@@ -28,6 +29,7 @@ class CredentialDetailsStore {
this.credentialId = credentialId; this.credentialId = credentialId;
this.history = []; this.history = [];
this._credential = await rootStore.agentStore.agent.credentials.getById(credentialId); this._credential = await rootStore.agentStore.agent.credentials.getById(credentialId);
this.credentialFormatData = await rootStore.agentStore.agent.credentials.getFormatData(credentialId);
await this._loadHistory(); await this._loadHistory();
this.loading = false; this.loading = false;
}; };
......
...@@ -13,6 +13,7 @@ import InfoSvg from 'src/assets/svg/info.svg'; ...@@ -13,6 +13,7 @@ import InfoSvg from 'src/assets/svg/info.svg';
import ActivitiesSvg from 'src/assets/svg/activities.svg'; import ActivitiesSvg from 'src/assets/svg/activities.svg';
import CredentialDetailsStore from "./CredentialDetailsStore"; import CredentialDetailsStore from "./CredentialDetailsStore";
import Loader from "src/components/Loader"; import Loader from "src/components/Loader";
import JsonLdCredentialViewer from "src/components/jsonld/JsonLdCredentialViewer";
type CredentialDetailsProps = StackScreenProps< type CredentialDetailsProps = StackScreenProps<
CredentialStackParams, CredentialStackParams,
...@@ -52,6 +53,9 @@ const CredentialDetails: React.FC<CredentialDetailsProps> = observer(({ ...@@ -52,6 +53,9 @@ const CredentialDetails: React.FC<CredentialDetailsProps> = observer(({
); );
} }
const jsonldCredential = store.credentialFormatData?.credential?.jsonld as any || null;
return ( return (
<ScrollView contentContainerStyle={styles.scrollView}> <ScrollView contentContainerStyle={styles.scrollView}>
<StatusBar barStyle="light-content" /> <StatusBar barStyle="light-content" />
...@@ -82,9 +86,13 @@ const CredentialDetails: React.FC<CredentialDetailsProps> = observer(({ ...@@ -82,9 +86,13 @@ const CredentialDetails: React.FC<CredentialDetailsProps> = observer(({
</View> </View>
); );
})} })}
{!!jsonldCredential && (
<JsonLdCredentialViewer jsonld={jsonldCredential} />
)}
</View> </View>
</View> </View>
<View style={styles.card}> <View style={styles.card}>
<View style={styles.header}> <View style={styles.header}>
<ActivitiesSvg style={styles.headerIcon} /> <ActivitiesSvg style={styles.headerIcon} />
...@@ -181,4 +189,8 @@ const styles = StyleSheet.create({ ...@@ -181,4 +189,8 @@ const styles = StyleSheet.create({
primaryColor: { primaryColor: {
color: ColorPallet.brand.primary, color: ColorPallet.brand.primary,
}, },
jsonld: {
...TextTheme.normal,
color: ColorPallet.baseColors.black
},
}); });
...@@ -17,6 +17,7 @@ import Button, {ButtonType} from "src/components/Button"; ...@@ -17,6 +17,7 @@ import Button, {ButtonType} from "src/components/Button";
import Record from "src/components/Record"; import Record from "src/components/Record";
import Title from "src/components/Title"; import Title from "src/components/Title";
import {CredentialState} from "@aries-framework/core"; import {CredentialState} from "@aries-framework/core";
import JsonLdCredentialViewer from "src/components/jsonld/JsonLdCredentialViewer";
type CredentialOfferProps = StackScreenProps< type CredentialOfferProps = StackScreenProps<
NotificationStackParams, NotificationStackParams,
...@@ -66,8 +67,10 @@ const CredentialOffer: React.FC<CredentialOfferProps> = observer(({ ...@@ -66,8 +67,10 @@ const CredentialOffer: React.FC<CredentialOfferProps> = observer(({
} }
}, [credential.state, connection]); }, [credential.state, connection]);
const redirectToHome = () => navigation.getParent()?.navigate(Screens.Credentials); const redirectToHome = () => navigation.getParent()?.navigate(Screens.Credentials);
const jsonLdData = store.credentialRecord?.offer?.jsonld as any || null;
const jsonldCredential = jsonLdData?.credential;
return ( return (
<> <>
<StatusBar barStyle="light-content" /> <StatusBar barStyle="light-content" />
...@@ -89,6 +92,11 @@ const CredentialOffer: React.FC<CredentialOfferProps> = observer(({ ...@@ -89,6 +92,11 @@ const CredentialOffer: React.FC<CredentialOfferProps> = observer(({
<CredentialCard credential={credential} /> <CredentialCard credential={credential} />
)} )}
</View> </View>
{!!jsonldCredential && (
<View style={styles.jsonldWrapper}>
<JsonLdCredentialViewer jsonld={jsonldCredential} />
</View>
)}
</> </>
)} )}
footer={() => ( footer={() => (
...@@ -183,4 +191,7 @@ const styles = StyleSheet.create({ ...@@ -183,4 +191,7 @@ const styles = StyleSheet.create({
paddingTop: 10, paddingTop: 10,
backgroundColor: ColorPallet.grayscale.white, backgroundColor: ColorPallet.grayscale.white,
}, },
jsonldWrapper: {
paddingHorizontal: 16,
}
}); });
...@@ -22,6 +22,8 @@ import { ...@@ -22,6 +22,8 @@ import {
ProofsModule, ProofsModule,
V2CredentialProtocol, V2CredentialProtocol,
V2ProofProtocol, V2ProofProtocol,
W3cCredentialService,
W3cCredentialsModule,
WsOutboundTransport, WsOutboundTransport,
} from "@aries-framework/core"; } from "@aries-framework/core";
import { agentDependencies } from "@aries-framework/react-native"; import { agentDependencies } from "@aries-framework/react-native";
...@@ -79,6 +81,7 @@ import TrustedEmailSender from "../db-models/TrustedEmailSender"; ...@@ -79,6 +81,7 @@ import TrustedEmailSender from "../db-models/TrustedEmailSender";
import axios from "axios"; import axios from "axios";
import { NativeModules } from "react-native"; import { NativeModules } from "react-native";
import { addHours } from "date-fns"; import { addHours } from "date-fns";
import { JsonLdCredentialFormatService } from "../credo/JsonLdCredentialFormatService";
const { VereignImapModule } = NativeModules; const { VereignImapModule } = NativeModules;
...@@ -162,6 +165,7 @@ class AgentStore { ...@@ -162,6 +165,7 @@ class AgentStore {
credentialFormats: [ credentialFormats: [
legacyIndyCredentialFormatService, legacyIndyCredentialFormatService,
new AnonCredsCredentialFormatService(), new AnonCredsCredentialFormatService(),
new JsonLdCredentialFormatService()
], ],
}), }),
], ],
...@@ -211,6 +215,7 @@ class AgentStore { ...@@ -211,6 +215,7 @@ class AgentStore {
// mediatorPickupStrategy: MediatorPickupStrategy.Implicit, // mediatorPickupStrategy: MediatorPickupStrategy.Implicit,
mediatorInvitationUrl: Config.MEDIATOR_URL, mediatorInvitationUrl: Config.MEDIATOR_URL,
}), }),
w3c: new W3cCredentialsModule()
}; };
const newAgent = new Agent({ const newAgent = new Agent({
...@@ -219,6 +224,12 @@ class AgentStore { ...@@ -219,6 +224,12 @@ class AgentStore {
modules, modules,
}); });
const w3cCredentialService = newAgent.context.dependencyManager.resolve(W3cCredentialService);
// TODO Hack dor demo purpose
// @ts-ignore
w3cCredentialService.verifyCredential = () => ({ isValid: true })
newAgent.registerOutboundTransport(new WsOutboundTransport()); newAgent.registerOutboundTransport(new WsOutboundTransport());
newAgent.registerOutboundTransport(new HttpOutboundTransport()); newAgent.registerOutboundTransport(new HttpOutboundTransport());
......
...@@ -78,6 +78,9 @@ export function parsedCredentialDefinition( ...@@ -78,6 +78,9 @@ export function parsedCredentialDefinition(
} }
export function hashCode(s: string): number { export function hashCode(s: string): number {
if (!s) {
return 0;
}
return s return s
.split('') .split('')
.reduce((hash, char) => char.charCodeAt(0) + ((hash << 5) - hash), 0); .reduce((hash, char) => char.charCodeAt(0) + ((hash << 5) - hash), 0);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment