Add hashing of user ID's by default

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>
This commit is contained in:
Jonathan Mezach
2023-07-12 16:52:33 +02:00
parent 541418c1ff
commit 9c87feae32
2 changed files with 64 additions and 3 deletions
@@ -74,6 +74,32 @@ app:
This plugin supports sending user context to New Relic Browser by providing a User ID. This requires instantiating the `NewRelicBrowser` instance with an `identityApi` instance passed to it, but this is optional. If omitted the plugin will not send user context to New Relic Browser.
By default the user ID is calculated as a SHA-256 hash of the current user's `userEntityRef` as returned by the `identityApi`. To set a
different value, provide a `userIdTransform` function alongside `identityApi` when you instantiate `NewRelicBrowser`. This function will be passed the `userEntityRef` as an argument and should resolve to the value you wish to set as the user ID. For example:
```typescript
import {
analyticsApiRef,
configApiRef,
identityApiRef,
} from '@backstage/core-plugin-api';
import { GoogleAnalytics } from '@backstage/plugin-analytics-module-newrelic-browser';
export const apis: AnyApiFactory[] = [
createApiFactory({
api: analyticsApiRef,
deps: { configApi: configApiRef, identityApi: identityApiRef },
factory: ({ configApi, identityApi }) =>
NewRelicBrowser.fromConfig(configApi, {
identityApi,
userIdTransform: async (userEntityRef: string): Promise<string> => {
return customHashingFunction(userEntityRef);
},
}),
}),
];
```
## Development
If you would like to contribute improvements to this plugin, the easiest way to
@@ -43,6 +43,7 @@ export class NewRelicBrowser implements AnalyticsApi {
private constructor(
options: NewRelicBrowserOptions,
identityApi?: IdentityApi,
userIdTransform?: 'sha-256' | ((userEntityRef: string) => Promise<string>),
) {
// Configure the New Relic Browser agent
const agentOptions = {
@@ -76,14 +77,31 @@ export class NewRelicBrowser implements AnalyticsApi {
// Initialize the agent
this.agent = new BrowserAgent(agentOptions) as unknown as NewRelicAPI;
// Check if identity has been provided
if (identityApi) {
identityApi.getBackstageIdentity().then(identity => {
this.agent.setUserId(identity.userEntityRef);
if (typeof userIdTransform === 'function') {
userIdTransform(identity.userEntityRef).then(userId => {
this.agent.setUserId(userId);
});
} else {
this.hash(identity.userEntityRef).then(userId => {
this.agent.setUserId(userId);
});
}
});
}
}
static fromConfig(config: Config, options: { identityApi?: IdentityApi }) {
static fromConfig(
config: Config,
options: {
identityApi?: IdentityApi;
userIdTransform?:
| 'sha-256'
| ((userEntityRef: string) => Promise<string>);
},
) {
const browserOptions: NewRelicBrowserOptions = {
endpoint: config.getString('app.analytics.nr.endpoint'),
accountId: config.getString('app.analytics.nr.accountId'),
@@ -96,7 +114,11 @@ export class NewRelicBrowser implements AnalyticsApi {
cookiesEnabled:
config.getOptionalBoolean('app.analytics.nr.cookiesEnabled') ?? false,
};
return new NewRelicBrowser(browserOptions, options.identityApi);
return new NewRelicBrowser(
browserOptions,
options.identityApi,
options.userIdTransform,
);
}
captureEvent(event: AnalyticsEvent) {
@@ -138,4 +160,17 @@ export class NewRelicBrowser implements AnalyticsApi {
this.agent.addPageAction(action, customAttributes);
}
}
/**
* Simple hash function; relies on web cryptography + the sha-256 algorithm.
* @param value value to be hashed
*/
private async hash(value: string): Promise<string> {
const digest = await window.crypto.subtle.digest(
'sha-256',
new TextEncoder().encode(value),
);
const hashArray = Array.from(new Uint8Array(digest));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
}