diff --git a/apps/learn-card-app/src/pages/consentFlow/ConsentFlowHeader.tsx b/apps/learn-card-app/src/pages/consentFlow/ConsentFlowHeader.tsx index d58e505fbc..59a5a2cd54 100644 --- a/apps/learn-card-app/src/pages/consentFlow/ConsentFlowHeader.tsx +++ b/apps/learn-card-app/src/pages/consentFlow/ConsentFlowHeader.tsx @@ -80,7 +80,7 @@ const ConsentFlowHeader: React.FC = ({ - {name} + {name}!!!!???????? ); diff --git a/apps/learn-card-app/src/pages/consentFlow/FullScreenConsentFlow.tsx b/apps/learn-card-app/src/pages/consentFlow/FullScreenConsentFlow.tsx index 1bcc91bb0d..8bd7e44d60 100644 --- a/apps/learn-card-app/src/pages/consentFlow/FullScreenConsentFlow.tsx +++ b/apps/learn-card-app/src/pages/consentFlow/FullScreenConsentFlow.tsx @@ -122,13 +122,15 @@ const FullScreenConsentFlow: React.FC = ({ } setStep(ConsentFlowStep.connecting); - + console.log('CONSENTING TO CONTRACT!!!!!!!!!!!!!'); try { const { redirectUrl } = await consentToContract({ terms, expiresAt: shareDuration.customDuration, oneTime: shareDuration.oneTimeShare, }); + console.log('redirectUrl', redirectUrl); + return; // Sync any auto-boost credentials (if any). No need to wait. fetchNewContractCredentials(); diff --git a/apps/learn-card-app/src/pages/launchPad/LaunchPad.tsx b/apps/learn-card-app/src/pages/launchPad/LaunchPad.tsx index 0dc5648a86..d706a56d8d 100644 --- a/apps/learn-card-app/src/pages/launchPad/LaunchPad.tsx +++ b/apps/learn-card-app/src/pages/launchPad/LaunchPad.tsx @@ -128,6 +128,8 @@ const LaunchPad: React.FC = () => { consentedContractLoading, hasConsented, } = useConsentFlowByUri(contractUri); + console.log('contractDetails', contractDetails); + console.log('contractUri', contractUri); useEffect(() => { if (contractDetails && !suppressContractModal && !consentedContractLoading) { @@ -212,7 +214,7 @@ const LaunchPad: React.FC = () => { return false; } - if (item?.displayInLaunchPad === false) return false; // for apps + // if (item?.displayInLaunchPad === false) return false; // for apps return contractName?.includes(lowerSearch) || appName?.includes(lowerSearch); }); diff --git a/packages/learn-card-base/src/hooks/useSharedUrisInTerms.ts b/packages/learn-card-base/src/hooks/useSharedUrisInTerms.ts index 9cd0ff067f..a317332468 100644 --- a/packages/learn-card-base/src/hooks/useSharedUrisInTerms.ts +++ b/packages/learn-card-base/src/hooks/useSharedUrisInTerms.ts @@ -37,15 +37,23 @@ export const getOrCreateSharedUriForWallet = async ( // For SmartResume we want to add the generic brain-service wallet's did so that the brain service // can decrypt the credentials and send them to SmartResume via their API - const isSmartResume = + const isSmartResume = true; + const isSmartResume2 = contractOwnerDid === 'did:web:network.learncard.com:users:smart-resume-integration' || contractOwnerDid === 'did:web:localhost%3A4000:users:in-service' || contractOwnerDid === 'did:web:localhost%3A4000:users:smart-resume' || + contractOwnerDid === 'did:web:testnet.network.learncard.com:users:testorg1' || + contractOwnerDid === 'did:web:staging.network.learncard.com:users:testorg1' || contractOwnerDid === 'did:web:localhost%3A4000:users:smart-resume-test'; const recipients = [contractOwnerDid]; + console.log('contractOwnerDid', contractOwnerDid); + console.log('isSmartResume', isSmartResume); + console.log('isSmartResume2', isSmartResume2); if (isSmartResume) { + recipients.push('did:web:testnet.network.learncard.com'); + recipients.push('did:web:staging.network.learncard.com'); recipients.push('did:web:network.learncard.com'); recipients.push('did:web:localhost%3A4000'); } diff --git a/services/learn-card-network/brain-service/src/helpers/boost.helpers.ts b/services/learn-card-network/brain-service/src/helpers/boost.helpers.ts index 0acf4c03bf..cef043af2b 100644 --- a/services/learn-card-network/brain-service/src/helpers/boost.helpers.ts +++ b/services/learn-card-network/brain-service/src/helpers/boost.helpers.ts @@ -316,6 +316,7 @@ export const sendBoost = async ({ skipNotification = false, autoAcceptCredential = false, contractTerms, + skipCertification = false, }: { from: ProfileType; to: ProfileType; @@ -325,12 +326,18 @@ export const sendBoost = async ({ skipNotification?: boolean; autoAcceptCredential?: boolean; contractTerms?: DbTermsType; + skipCertification?: boolean; }): Promise => { const decryptedCredential = await decryptCredential(credential); let boostUri: string | undefined; if (decryptedCredential) { if (process.env.NODE_ENV !== 'test') console.log('🚀 sendBoost:VC Decrypted'); - const certifiedBoost = await issueCertifiedBoost(boost, decryptedCredential, domain); + let certifiedBoost: VC | JWE | false; + if (skipCertification) { + certifiedBoost = decryptedCredential; + } else { + certifiedBoost = await issueCertifiedBoost(boost, decryptedCredential, domain); + } if (certifiedBoost) { const credentialInstance = await storeCredential(certifiedBoost); diff --git a/services/learn-card-network/brain-service/src/helpers/uri.helpers.ts b/services/learn-card-network/brain-service/src/helpers/uri.helpers.ts index 52d50a39e3..a3da3eea35 100644 --- a/services/learn-card-network/brain-service/src/helpers/uri.helpers.ts +++ b/services/learn-card-network/brain-service/src/helpers/uri.helpers.ts @@ -9,7 +9,15 @@ import { isEncrypted } from '@learncard/helpers'; import { TRPCError } from '@trpc/server'; import { getLearnCard } from './learnCard.helpers'; -export const URI_TYPES = ['credential', 'presentation', 'boost', 'contract', 'terms', 'framework', 'skill'] as const; +export const URI_TYPES = [ + 'credential', + 'presentation', + 'boost', + 'contract', + 'terms', + 'framework', + 'skill', +] as const; export type URIType = (typeof URI_TYPES)[number]; @@ -37,7 +45,13 @@ export const getUriParts = (_uri: string, allowOutsideUris: boolean = false): UR }); } - const [lc, method, domain, type, ...rest] = parts as [string, string, string, string, ...string[]]; + const [lc, method, domain, type, ...rest] = parts as [ + string, + string, + string, + string, + ...string[] + ]; const id = rest.join(':'); if ((lc !== 'lc' || method !== 'network') && !allowOutsideUris) { @@ -61,9 +75,7 @@ export const constructUri = (type: URIType, id: string, domain: string): string // Helper specifically for skill URIs which must be of the form // lc:network:/trpc:skill:: -export const getSkillCompoundFromUri = ( - uri: string -): { frameworkId: string; id: string } => { +export const getSkillCompoundFromUri = (uri: string): { frameworkId: string; id: string } => { const { type, id } = getUriParts(uri); if (type !== 'skill') { @@ -84,19 +96,47 @@ export const getSkillCompoundFromUri = ( export const resolveUri = async (uri: string) => { const { domain, type, method } = getUriParts(uri, true); - + console.log('uri', uri); + console.log('Parsed URI parts:', { domain, type, method }); if (method === 'cloud') { const isLocal = domain.includes('localhost'); const url = `http${isLocal ? '' : 's'}://${domain .replace('%3A', ':') .replace('/trpc', '/api')}/storage/resolve?uri=${encodeURIComponent(uri)}`; - + console.log('url', url); const res = await fetch(url); + console.log('res', res); const resolved = await res.json(); + console.log('resolved', resolved); if (isEncrypted(resolved)) { - const learnCard = await getLearnCard(); - - return await learnCard.invoke.decryptDagJwe(resolved); + try { + const learnCard = await getLearnCard(); + console.log('JWE Structure:', { + protected: resolved.protected, + recipients: Array.isArray(resolved.recipients) + ? resolved.recipients.map((r: any) => ({ + header: r.header, //should show DID + encrypted_key: r.encrypted_key ? '***' : undefined, + })) + : resolved.recipients, + iv: resolved.iv ? '***' : undefined, + ciphertext: resolved.ciphertext ? '***' : undefined, + tag: resolved.tag ? '***' : undefined, + }); + + const decryptResolved = await learnCard.invoke.decryptDagJwe(resolved); + console.log('decryptResolved', decryptResolved); + + return decryptResolved; + } catch (error) { + // console.error('Error in decryptDagJwe:', { + // message: error.message, + // stack: error.stack, + // name: error.name, + // error: error, + // }); + throw error; + } } return resolved; } diff --git a/services/learn-card-network/brain-service/src/routes/contracts.ts b/services/learn-card-network/brain-service/src/routes/contracts.ts index 272b0d53fc..89bc3ee580 100644 --- a/services/learn-card-network/brain-service/src/routes/contracts.ts +++ b/services/learn-card-network/brain-service/src/routes/contracts.ts @@ -673,6 +673,7 @@ export const contractsRouter = t.router({ skipNotification: true, autoAcceptCredential: false, contractTerms: terms, + skipCertification: true, }); }), @@ -927,14 +928,11 @@ export const contractsRouter = t.router({ let redirectUrl: string | undefined; // SmartResume handling - const isSmartResume = - contractUri === process.env.SMART_RESUME_CONTRACT_URI || - contractUri === - 'lc:network:network.learncard.com/trpc:contract:55b738f0-49f4-4b33-b6c1-afa99b605cd6'; // hardcode for quick fix purposes + const isSmartResume = true; // hardcode for quick fix purposes if (isSmartResume) { - if (!recipientToken) { - throw new Error('Missing recipientToken for SmartResume'); - } + // if (!recipientToken) { + // throw new Error('Missing recipientToken for SmartResume'); + // } const isProduction = !process.env.IS_OFFLINE; @@ -955,6 +953,7 @@ export const contractsRouter = t.router({ scope: 'delete readonly replace', }), }).then(res => res.json())) as { access_token?: string }; + console.log('accessTokenResponse', accessTokenResponse); const accessToken = accessTokenResponse.access_token; if (!accessToken) throw new Error('Missing access_token for SmartResume'); @@ -968,7 +967,7 @@ export const contractsRouter = t.router({ // filter out duplicates ...new Set(categoryValues.flatMap(({ shared }) => shared ?? [])), ]; - + console.log('allSharedCredentialUris', allSharedCredentialUris); const resolvedCredentials = await Promise.all( allSharedCredentialUris.map(async uri => { try { @@ -979,7 +978,7 @@ export const contractsRouter = t.router({ } }) ); - + console.log('resolvedCredentials', resolvedCredentials); type ResolvedCredential = { issuer?: string | { id: string }; id?: string; @@ -996,19 +995,19 @@ export const contractsRouter = t.router({ ? ({ ...cred.boostCredential, id: cred.id } as ResolvedCredential) // unwrap credential, preserve id : cred ); - - const transformedCredentials = credentials.map(cred => { - const issuer = - typeof cred.issuer === 'string' - ? { id: cred.issuer } - : cred.issuer || { id: '' }; - - return { - ...cred, - issuer, - }; - }); - + console.log('credentials', credentials); + // const transformedCredentials = credentials.map(cred => { + // const issuer = + // typeof cred.issuer === 'string' + // ? { id: cred.issuer } + // : cred.issuer || { id: '' }; + + // return { + // ...cred, + // issuer, + // }; + // }); + // console.log('transformedCredentials', transformedCredentials); const { name, email } = parsedTerms.read.personal; const body = JSON.stringify({ @@ -1024,24 +1023,34 @@ export const contractsRouter = t.router({ familyName: '', // this is neecessary in order for givenName to be respected email: email && email !== 'anonymous@hidden.com' ? email : '', }, - credentials: transformedCredentials, + credentials: credentials, }); - + console.log('body', body); try { const response = await fetch(`${srUrl}api/v1/credentials`, { method: 'POST', headers: { - Authorization: `Bearer ${accessToken}`, + 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json', }, body, }); + const responseBody = await response.text(); + console.log('SmartResume API Response:', responseBody); + if (!response.ok) { - throw new Error(`Error (${response.status}): ${await response.text()}`); + throw new Error(`Error (${response.status}): ${responseBody}`); + } + + let result; + try { + result = JSON.parse(responseBody); + } catch (e) { + throw new Error(`Failed to parse response: ${responseBody}`); } - const result = (await response.json()) as { redirect_url?: string }; + console.log('Parsed response:', result); redirectUrl = result.redirect_url; } catch (error) { console.error('Error uploading credentials to SmartResume:', error); diff --git a/services/learn-card-network/lca-api/src/routes/credentials.ts b/services/learn-card-network/lca-api/src/routes/credentials.ts index bd4e06a28b..bcde7c3638 100644 --- a/services/learn-card-network/lca-api/src/routes/credentials.ts +++ b/services/learn-card-network/lca-api/src/routes/credentials.ts @@ -50,7 +50,9 @@ export const credentialsRouter = t.router({ signingAuthority.name ); - credential.issuer = learnCard.id.did(); + // credential.issuer = learnCard.id.did(); + credential.issuer = { id: learnCard.id.did() }; + const verificationMethod = learnCard.id.did().startsWith('did:web') ? `${learnCard.id.did()}#${signingAuthority.name}` : undefined;