Skip to content

Commit

Permalink
Added logger and some usage (#947)
Browse files Browse the repository at this point in the history
  • Loading branch information
thehenrytsai authored Oct 4, 2024
1 parent 101f463 commit a2cd9d5
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 4 deletions.
3 changes: 2 additions & 1 deletion packages/agent/src/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from './oidc.js';
import { pollWithTtl } from './utils.js';

import { Convert } from '@web5/common';
import { Convert, logger } from '@web5/common';
import { CryptoUtils } from '@web5/crypto';
import { DidJwk } from '@web5/dids';
import { DwnInterfaceName, DwnMethodName } from '@tbd54566975/dwn-sdk-js';
Expand Down Expand Up @@ -94,6 +94,7 @@ async function initClient({

// a deeplink to a web5 compatible wallet. if the wallet scans this link it should receive
// a route to its web5 connect provider flow and the params of where to fetch the auth request.
logger.log(`Wallet URI: ${walletUri}`);
const generatedWalletUri = new URL(walletUri);
generatedWalletUri.searchParams.set('request_uri', parData.request_uri);
generatedWalletUri.searchParams.set(
Expand Down
23 changes: 20 additions & 3 deletions packages/agent/src/oidc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Convert, RequireOnly } from '@web5/common';
import { Convert, logger, RequireOnly } from '@web5/common';
import {
Ed25519,
EdDsaAlgorithm,
Expand Down Expand Up @@ -631,6 +631,7 @@ async function createPermissionGrants(
const permissionsApi = new AgentPermissionsApi({ agent });

// TODO: cleanup all grants if one fails by deleting them from the DWN: https://github.com/TBD54566975/web5-js/issues/849
logger.log(`Creating permission grants for ${scopes.length} scopes given...`);
const permissionGrants = await Promise.all(
scopes.map((scope) => {
// check if the scope is a records permission scope, or a protocol configure scope, if so it should use a delegated permission.
Expand All @@ -646,6 +647,7 @@ async function createPermissionGrants(
})
);

logger.log(`Sending ${permissionGrants.length} permission grants to remote DWN...`);
const messagePromises = permissionGrants.map(async (grant) => {
// Quirk: we have to pull out encodedData out of the message the schema validator doesn't want it there
const { encodedData, ...rawMessage } = grant.message;
Expand All @@ -661,6 +663,8 @@ async function createPermissionGrants(

// check if the message was sent successfully, if the remote returns 409 the message may have come through already via sync
if (reply.status.code !== 202 && reply.status.code !== 409) {
logger.error(`Error sending RecordsWrite: ${reply.status.detail}`);
logger.error(`RecordsWrite message: ${rawMessage}`);
throw new Error(
`Could not send the message. Error details: ${reply.status.detail}`
);
Expand All @@ -669,8 +673,13 @@ async function createPermissionGrants(
return grant.message;
});

const messages = await Promise.all(messagePromises);
return messages;
try {
const messages = await Promise.all(messagePromises);
return messages;
} catch (error) {
logger.error(`Error during batch-send of permission grants: ${error}`);
throw error;
}
}

/**
Expand All @@ -695,6 +704,8 @@ async function prepareProtocol(
`Could not fetch protocol: ${queryMessage.reply.status.detail}`
);
} else if (queryMessage.reply.entries === undefined || queryMessage.reply.entries.length === 0) {
logger.log(`Protocol does not exist, creating: ${protocolDefinition.protocol}`);

// send the protocol definition to the remote DWN first, if it passes we can process it locally
const { reply: sendReply, message: configureMessage } = await agent.sendDwnRequest({
author : selectedDid,
Expand All @@ -717,6 +728,8 @@ async function prepareProtocol(
});

} else {
logger.log(`Protocol already exists: ${protocolDefinition.protocol}`);

// the protocol already exists, let's make sure it exists on the remote DWN as the requesting app will need it
const configureMessage = queryMessage.reply.entries![0];
const { reply: sendReply } = await agent.sendDwnRequest({
Expand Down Expand Up @@ -776,6 +789,7 @@ async function submitAuthResponse(

const delegateGrants = (await Promise.all(delegateGrantPromises)).flat();

logger.log('Generating auth response object...');
const responseObject = await Oidc.createResponseObject({
//* the IDP's did that was selected to be connected
iss : selectedDid,
Expand All @@ -790,6 +804,7 @@ async function submitAuthResponse(
});

// Sign the Response Object using the ephemeral DID's signing key.
logger.log('Signing auth response object...');
const responseObjectJwt = await Oidc.signJwt({
did : delegateBearerDid,
data : responseObject,
Expand All @@ -801,6 +816,7 @@ async function submitAuthResponse(
clientDid?.didDocument!
);

logger.log('Encrypting auth response object...');
const encryptedResponse = Oidc.encryptAuthResponse({
jwt : responseObjectJwt!,
encryptionKey : sharedKey,
Expand All @@ -813,6 +829,7 @@ async function submitAuthResponse(
state : authRequest.state,
}).toString();

logger.log(`Sending auth response object to Web5 Connect server: ${authRequest.redirect_uri}`);
await fetch(authRequest.redirect_uri, {
body : formEncodedRequest,
method : 'POST',
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export type * from './types.js';

export * from './cache.js';
export * from './convert.js';
export * from './logger.js';
export * from './multicodec.js';
export * from './object.js';
export * from './stores.js';
Expand Down
70 changes: 70 additions & 0 deletions packages/common/src/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* Web5 logger level.
*/
export enum Web5LogLevel {
Debug = 'debug',
Silent = 'silent',
}

/**
* Web5 logger interface.
*/
export interface Web5LoggerInterface {

/**
* Sets the log verbose level.
*/
setLogLevel(logLevel: Web5LogLevel): void;

/**
* Same as `info()`.
* Logs an informational message.
*/
log (message: string): void;

/**
* Logs an informational message.
*/
info(message: string): void;

/**
* Logs an error message.
*/
error(message: string): void;
}

/**
* A Web5 logger implementation.
*/
class Web5Logger implements Web5LoggerInterface {
private logLevel: Web5LogLevel = Web5LogLevel.Silent; // Default to silent/no-op log level

setLogLevel(logLevel: Web5LogLevel): void {
this.logLevel = logLevel;
}

public log(message: string): void {
this.info(message);
}

public info(message: string): void {
if (this.logLevel === Web5LogLevel.Silent) { return; }

console.info(message);
}

public error(message: string): void {
if (this.logLevel === Web5LogLevel.Silent) { return; }

console.error(message);
}
}

// Export a singleton logger instance
export const logger = new Web5Logger();

// Attach logger to the global window object in browser environment for easy access to the logger instance.
// e.g. can call `web5logger.setLogLevel('debug');` directly in browser console.
if (typeof window !== 'undefined') {
(window as any).web5logger = logger; // Makes `web5Logger` accessible globally in browser
}

0 comments on commit a2cd9d5

Please sign in to comment.