Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@adyen/bpscaweb

Package Overview
Dependencies
Maintainers
0
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@adyen/bpscaweb - npm Package Compare versions

Comparing version 0.0.2 to 0.1.0

dist/css/bootstrap.min.css

454

dist/es/bpscaweb.es.js

@@ -1,7 +0,1 @@

class ServerError extends Error {
constructor(errorResponse, ...params) {
super(...params);
this.errorResponse = errorResponse;
}
}
var base64Js = {};

@@ -102,3 +96,3 @@ base64Js.byteLength = byteLength;

const removeEmptyJsonElements = (obj) => {
Object.keys(obj).forEach(function(key) {
Object.keys(obj).forEach((key) => {
obj[key] && typeof obj[key] === "object" && removeEmptyJsonElements(obj[key]) || (obj[key] === "" || obj[key] === null) && delete obj[key];

@@ -109,7 +103,7 @@ });

const getBaseUrl = () => {
const pathArray = window.location.href.split("/");
const protocol = pathArray[0];
const host = pathArray[2];
const baseUrl = protocol + "//" + host;
return baseUrl;
const {
host,
protocol
} = new URL(window.location.href);
return `${protocol}//${host}`;
};

@@ -122,7 +116,7 @@ const getHostName = () => {

};
const base64urlToUint8array = (base64Bytes) => {
const base64ToUint8array = (base64Bytes) => {
const padding = "====".substring(0, (4 - base64Bytes.length % 4) % 4);
return base64Js.toByteArray((base64Bytes + padding).replace(/\//g, "_").replace(/\+/g, "-"));
return base64Js.toByteArray(base64Bytes + padding);
};
const uint8arrayToBase64url = (bytes) => {
const uint8arrayToBase64 = (bytes) => {
if (!bytes) {

@@ -132,328 +126,131 @@ return "";

if (bytes instanceof Uint8Array) {
return base64Js.fromByteArray(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
return base64Js.fromByteArray(bytes);
}
return uint8arrayToBase64url(new Uint8Array(bytes));
return uint8arrayToBase64(new Uint8Array(bytes));
};
function createCredential(registrationInitiationResponse) {
const formattedPublicKey = {
const authenticateWithCredential = (publicKeyCredentialRequestOptions) => {
var _a;
const credentialGetOptions = {
publicKey: {
...registrationInitiationResponse.publicKeyCredentialCreationOptions,
challenge: base64urlToUint8array(registrationInitiationResponse.publicKeyCredentialCreationOptions.challenge),
user: {
...registrationInitiationResponse.publicKeyCredentialCreationOptions.user,
id: base64urlToUint8array(registrationInitiationResponse.publicKeyCredentialCreationOptions.user.id)
}
...publicKeyCredentialRequestOptions,
challenge: base64ToUint8array(publicKeyCredentialRequestOptions.challenge)
}
};
return navigator.credentials.create(formattedPublicKey);
}
function buildRegistrationInitiationRequest({
deviceName,
originUrl,
relyingPartyId,
relyingPartyName,
correlation
}) {
const registrationInitiationRequest = {
device: {
name: deviceName,
type: "browser"
},
origin: {
url: originUrl,
platform: "web"
},
correlation: {
id: correlation.correlationId,
type: correlation.correlationType,
state: "state2"
},
rp: {
id: relyingPartyId,
name: relyingPartyName
}
};
const registrationInitiationRequestWrapped = {
correlationId: correlation.correlationId,
strongCustomerAuthentication: {
sdkOutput: btoa(JSON.stringify(registrationInitiationRequest))
}
};
return registrationInitiationRequestWrapped;
}
async function requestDevice(startRegisterDeviceUrl, data, headerOptions) {
const response = await fetch(startRegisterDeviceUrl, {
method: "POST",
headers: {
...headerOptions,
"Content-Type": "application/json"
},
body: JSON.stringify(data)
// body data type must match "Content-Type" header
});
return response;
}
function initiateRegistration(request) {
const registrationInitiationRequestWrapped = buildRegistrationInitiationRequest(request);
const {
configuration
} = request;
return requestDevice(configuration.startRegisterDeviceUrl, registrationInitiationRequestWrapped, configuration.globalHeaders).then((response) => {
if (response.ok) {
return response.json();
}
return response.json().then((response2) => {
throw new ServerError(response2, "Error occurred during registration initiation stage");
});
});
}
function buildRegistrationFinalisationRequest({
deviceReference,
publicKeyCredential,
relyingPartyId,
relyingPartyName,
originUrl,
correlation
}) {
const registerResponse = publicKeyCredential.response;
const formattedPublicKeyCredential = {
if ((_a = credentialGetOptions.publicKey) == null ? void 0 : _a.allowCredentials) {
credentialGetOptions.publicKey.allowCredentials = credentialGetOptions.publicKey.allowCredentials.map((cred) => ({
...cred,
id: base64ToUint8array(cred.id)
}));
}
return navigator.credentials.get(credentialGetOptions);
};
function createFormattedPublicKeyCredential(publicKeyCredential) {
const credentialResponse = publicKeyCredential.response;
return {
type: publicKeyCredential.type,
id: publicKeyCredential.id,
type: publicKeyCredential.type,
rp: {
id: relyingPartyId,
name: relyingPartyName
},
rawId: uint8arrayToBase64(publicKeyCredential.rawId),
response: {
attestationObject: uint8arrayToBase64url(registerResponse.attestationObject),
clientDataJSON: uint8arrayToBase64url(registerResponse.clientDataJSON),
transports: registerResponse.getTransports() || []
authenticatorData: uint8arrayToBase64(credentialResponse.authenticatorData),
clientDataJSON: uint8arrayToBase64(credentialResponse.clientDataJSON),
signature: uint8arrayToBase64(credentialResponse.signature),
userHandle: uint8arrayToBase64(credentialResponse.userHandle)
}
};
const registrationFinalisationRequest = {
publicKeyCredential: formattedPublicKeyCredential,
device: {
type: "browser"
},
origin: {
url: originUrl,
platform: "web"
},
correlation: {
id: correlation.correlationId,
type: correlation.correlationType,
state: "state2"
}
};
const registrationFinalisationRequestWrapped = {
correlationId: correlation.correlationId,
strongCustomerAuthentication: {
sdkOutput: btoa(JSON.stringify(registrationFinalisationRequest))
},
id: deviceReference
};
return registrationFinalisationRequestWrapped;
}
async function confirmDevice(finishRegisterDeviceUrl, data, headerOptions) {
const response = await fetch(finishRegisterDeviceUrl, {
method: "POST",
headers: {
...headerOptions,
"Content-Type": "application/json"
},
body: JSON.stringify(data)
// body data type must match "Content-Type" header
function authenticate(sdkInput) {
const unwrappedResponseJsonStr = atob(sdkInput);
const json = removeEmptyJsonElements(JSON.parse(unwrappedResponseJsonStr));
return authenticateWithCredential(json.publicKeyCredentialRequestOptions).then((credential) => {
const publicKeyCredential = credential;
const authenticationRequest = {
device: "browser",
origin: getBaseUrl(),
rp: {
id: getHostName()
},
traceparent: json.traceparent,
publicKeyCredential: createFormattedPublicKeyCredential(publicKeyCredential)
};
return btoa(JSON.stringify(authenticationRequest));
});
return response;
}
function finaliseRegistration(request) {
const registrationFinalisationRequestWrapped = buildRegistrationFinalisationRequest(request);
const {
configuration
} = request;
return confirmDevice(configuration.finishRegisterDeviceUrl, registrationFinalisationRequestWrapped, configuration.globalHeaders).then((response) => {
if (response.ok) {
return response;
}
return response.json().then((response2) => {
throw new ServerError(response2, "Error occurred during registration finalisation stage");
});
});
class SCAUnavailableError extends Error {
constructor(message) {
super(message);
this.code = "SCA_UNAVAILABLE";
}
}
function registerDevice(request) {
let deviceReference = void 0;
const originUrl = getBaseUrl();
const relyingPartyId = getHostName();
return initiateRegistration({
...request,
originUrl,
relyingPartyId
}).then((registrationInitiationResponse) => {
deviceReference = registrationInitiationResponse.id;
const unwrappedResponseJsonStr = atob(registrationInitiationResponse.sdkInput);
return removeEmptyJsonElements(JSON.parse(unwrappedResponseJsonStr));
}).then((registrationInitiationResponse) => {
return createCredential(registrationInitiationResponse);
}).then((publicKeyCredential) => ({
publicKeyCredential,
relyingPartyId,
relyingPartyName: request.relyingPartyName,
originUrl,
correlation: request.correlation,
deviceReference,
configuration: request.configuration
})).then((finishRequest) => {
return finaliseRegistration(finishRequest);
}).catch((ex) => {
console.error("Error performing registration: " + ex);
throw ex;
});
}
const WWW_AUTHENTICATE_HEADER_KEY = "WWW-Authenticate";
const AUTH_PARAM_HEADER_KEY = "auth-param1";
const SCA_REALM_HEADER_KEY = "SCA realm";
const HTTP_UNAUTHORISED = 401;
function isHttp2xxStatus(status) {
return status == 200 || status == 201 || status == 202 || status == 203 || status == 204;
}
function executeAuthenticatedHttpRequest(privilegedRequest, wwwAuthenticateHeader) {
return fetch(privilegedRequest.url, {
headers: {
...privilegedRequest.headers,
[WWW_AUTHENTICATE_HEADER_KEY]: wwwAuthenticateHeader
},
method: privilegedRequest.operation,
body: privilegedRequest.body
});
}
function extractAuthParam1(wwwAuthenticateHeader) {
if (!wwwAuthenticateHeader || wwwAuthenticateHeader.indexOf(AUTH_PARAM_HEADER_KEY) == -1) {
throw new Error(`Incorrect format for ${WWW_AUTHENTICATE_HEADER_KEY} header, expected ${AUTH_PARAM_HEADER_KEY} key`);
}
var parts = wwwAuthenticateHeader.split(" ");
var authParam1Value = void 0;
for (var i = 0; i < parts.length; i++) {
if (parts[i].startsWith(AUTH_PARAM_HEADER_KEY)) {
if (parts[i].length > AUTH_PARAM_HEADER_KEY.length) {
authParam1Value = parts[i].substring(AUTH_PARAM_HEADER_KEY.length + 1);
function checkAvailability(configuration) {
if (window.PublicKeyCredential) {
return PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable().then((available) => {
if (available) {
const originUrl = getBaseUrl();
const relyingPartyId = getHostName();
const relyingPartyName = configuration.relyingPartyName;
const sdkOutput = {
device: "browser",
origin: originUrl,
rp: {
id: relyingPartyId,
name: relyingPartyName
}
};
return btoa(JSON.stringify(sdkOutput));
} else {
throw new SCAUnavailableError("No platform authenticator available");
}
}
});
} else {
throw new SCAUnavailableError("No PublicKeyCredential available");
}
if (!authParam1Value) {
throw new Error(`Incorrect format for ${WWW_AUTHENTICATE_HEADER_KEY} header, malformed ${AUTH_PARAM_HEADER_KEY}`);
}
return JSON.parse(atob(authParam1Value));
}
async function initiationAuthentication(privilegedRequest, device) {
const authenticationInitiationRequest = {
device: {
type: "browser"
},
origin: {
url: device.originUrl
},
rp: {
id: device.relyingPartyId
},
correlation: {
type: device.correlationType
}
};
const encodedAuthenticationInitiationRequest = btoa(JSON.stringify(authenticationInitiationRequest));
const wwwAuthenticateHeader = `${SCA_REALM_HEADER_KEY}="${privilegedRequest.scaRealm}" ${AUTH_PARAM_HEADER_KEY}=${encodedAuthenticationInitiationRequest}`;
return executeAuthenticatedHttpRequest(privilegedRequest, wwwAuthenticateHeader).then(async (response) => {
if (isHttp2xxStatus(response.status)) {
const responseBody = await response.text();
const privilegedRequestResponse = responseBody && responseBody.length > 0 ? JSON.parse(responseBody) : {};
const authenticationExempt = {
response: privilegedRequestResponse
};
console.log("Received HTTP 2xx status on authentication initiation, not proceeding with authentication");
return Promise.reject(authenticationExempt);
}
if (response.status == HTTP_UNAUTHORISED) {
let authenticationInitiationResponse = extractAuthParam1(response.headers.get(WWW_AUTHENTICATE_HEADER_KEY));
authenticationInitiationResponse = removeEmptyJsonElements(authenticationInitiationResponse);
return {
response: authenticationInitiationResponse
};
}
return response.json().then((response2) => {
throw new ServerError(response2, "Error occurred during authentication initiation stage");
});
}).then((authenticationInitiationResponse) => {
return authenticationInitiationResponse;
});
}
function authenticateWithCredential(authenticationInitiationResponse) {
const credentialGetOptions = {
const PUBLIC_KEY_ALGORITHMS = [-7, -8, -257];
function createCredential(registrationInitiationResponse) {
const formattedPublicKey = {
publicKey: {
...authenticationInitiationResponse.response.publicKeyCredentialRequestOptions,
challenge: base64urlToUint8array(authenticationInitiationResponse.response.publicKeyCredentialRequestOptions.challenge)
...registrationInitiationResponse.publicKeyCredentialCreationOptions,
challenge: base64ToUint8array(registrationInitiationResponse.publicKeyCredentialCreationOptions.challenge),
user: {
...registrationInitiationResponse.publicKeyCredentialCreationOptions.user,
id: base64ToUint8array(registrationInitiationResponse.publicKeyCredentialCreationOptions.user.id)
}
}
};
for (let i = 0; i < credentialGetOptions.publicKey.allowCredentials.length; i++) {
credentialGetOptions.publicKey.allowCredentials[i].id = base64urlToUint8array(credentialGetOptions.publicKey.allowCredentials[i].id);
if (formattedPublicKey.publicKey) {
formattedPublicKey.publicKey.pubKeyCredParams = formattedPublicKey.publicKey.pubKeyCredParams.filter((param) => PUBLIC_KEY_ALGORITHMS.includes(param.alg));
}
return navigator.credentials.get(credentialGetOptions);
return navigator.credentials.create(formattedPublicKey);
}
function buildAuthenticationFinalisationRequest(publicKeyCredential, device) {
const credentialResponse = publicKeyCredential.response;
const formattedPublicKeyCredential = {
type: publicKeyCredential.type,
id: publicKeyCredential.id,
rawId: uint8arrayToBase64url(publicKeyCredential.rawId),
response: {
authenticatorData: uint8arrayToBase64url(credentialResponse.authenticatorData),
clientDataJSON: uint8arrayToBase64url(credentialResponse.clientDataJSON),
signature: uint8arrayToBase64url(credentialResponse.signature),
userHandle: uint8arrayToBase64url(credentialResponse.userHandle)
}
};
const authenticationFinalisationRequest = {
device: {
type: "browser"
},
origin: {
url: device.originUrl
},
rp: {
id: device.relyingPartyId
},
correlation: {
type: device.correlationType
},
publicKeyCredential: formattedPublicKeyCredential
};
return authenticationFinalisationRequest;
}
async function finaliseAuthentication(privilegedRequest, publicKeyCredential, device) {
const authenticationFinalisationRequest = buildAuthenticationFinalisationRequest(publicKeyCredential, device);
const authParam1 = btoa(JSON.stringify(authenticationFinalisationRequest));
const wwwAuthenticateHeader = `${SCA_REALM_HEADER_KEY}="${privilegedRequest.scaRealm}" ${AUTH_PARAM_HEADER_KEY}=${authParam1}`;
return executeAuthenticatedHttpRequest(privilegedRequest, wwwAuthenticateHeader).then(async (privilegedResponse) => {
if (privilegedResponse.ok) {
const responseBody = await privilegedResponse.text();
const privilegedRequestResponse = responseBody && responseBody.length > 0 ? JSON.parse(responseBody) : {};
return privilegedRequestResponse;
}
return privilegedResponse.json().then((authenticationFinalisationResponse) => {
throw new ServerError(authenticationFinalisationResponse, "Error occurred during authentication finalisation stage");
});
});
}
async function performAuthenticatedRequest(privilegedRequest) {
const device = {
originUrl: getBaseUrl(),
function register(sdkInput, configuration) {
const unwrappedResponseJsonStr = atob(sdkInput);
const json = removeEmptyJsonElements(JSON.parse(unwrappedResponseJsonStr));
return createCredential(json).then((publicKeyCredential) => ({
publicKeyCredential,
relyingPartyId: getHostName(),
correlationType: privilegedRequest.correlationType
};
return initiationAuthentication(privilegedRequest, device).then((authenticationInitiationResponse) => {
return authenticationInitiationResponse;
}).then((authenticationInitiationResponse) => {
return authenticateWithCredential(authenticationInitiationResponse);
}).then((publicKeyCredential) => {
return finaliseAuthentication(privilegedRequest, publicKeyCredential, device);
}).catch((ex) => {
console.error("Error performing authentication: " + ex);
throw ex;
relyingPartyName: configuration.relyingPartyName,
originUrl: getBaseUrl()
})).then((request) => {
const publicKeyCredential = request.publicKeyCredential;
const registerResponse = publicKeyCredential.response;
const formattedPublicKeyCredential = {
id: uint8arrayToBase64(publicKeyCredential.rawId),
type: publicKeyCredential.type,
rp: {
id: request.relyingPartyId,
name: request.relyingPartyName
},
response: {
attestationObject: uint8arrayToBase64(registerResponse.attestationObject),
clientDataJSON: uint8arrayToBase64(registerResponse.clientDataJSON),
transports: registerResponse.getTransports() || []
}
};
const sdkOutput = {
publicKeyCredential: formattedPublicKeyCredential,
device: "browser",
origin: request.originUrl,
traceparent: json.traceparent
};
return btoa(JSON.stringify(sdkOutput));
});

@@ -468,16 +265,11 @@ }

}
registerDevice(request) {
request.configuration = {
...this.configuration,
...request.configuration
};
return registerDevice(request);
checkAvailability() {
return checkAvailability(this.configuration);
}
authorize(request) {
request.headers = {
...this.configuration.globalHeaders,
...request.headers
};
return performAuthenticatedRequest(request);
register(sdkInput) {
return register(sdkInput, this.configuration);
}
authenticate(sdkInput) {
return authenticate(sdkInput);
}
}

@@ -484,0 +276,0 @@ export {

@@ -1,2 +0,1 @@

import { PrivilegedRequest } from './types';
export declare function performAuthenticatedRequest(privilegedRequest: PrivilegedRequest): Promise<any>;
export declare function authenticate(sdkInput: string): Promise<String>;

@@ -1,5 +0,1 @@

export declare const WWW_AUTHENTICATE_HEADER_KEY = "WWW-Authenticate";
export declare const AUTH_PARAM_HEADER_KEY = "auth-param1";
export declare const SCA_REALM_HEADER_KEY = "SCA realm";
export declare const HTTP_OK = 200;
export declare const HTTP_UNAUTHORISED = 401;
export declare const PUBLIC_KEY_ALGORITHMS: number[];

@@ -1,2 +0,2 @@

import { RegistrationDeviceRequest } from './types';
export declare function registerDevice(request: RegistrationDeviceRequest): Promise<Response>;
import { ScaConfiguration } from './types';
export declare function register(sdkInput: string, configuration: ScaConfiguration): Promise<String>;

@@ -1,2 +0,2 @@

import { ScaConfiguration, RegistrationDeviceRequest, PrivilegedRequest } from './types';
import { ScaConfiguration } from './types';
export declare class ScaWebauthn {

@@ -6,4 +6,5 @@ private readonly configuration;

static create(configuration: ScaConfiguration): ScaWebauthn;
registerDevice(request: RegistrationDeviceRequest): Promise<Response>;
authorize(request: PrivilegedRequest): Promise<any>;
checkAvailability(): Promise<String>;
register(sdkInput: string): Promise<String>;
authenticate(sdkInput: string): Promise<String>;
}

@@ -1,49 +0,7 @@

export type scaProperties = {
deviceName: string;
partyName: string;
};
export type ScaConfiguration = {
startRegisterDeviceUrl: string;
finishRegisterDeviceUrl: string;
globalHeaders?: any;
relyingPartyName: string;
};
export declare enum CorrelationTypes {
paymentInstrument = "payment_instrument"
export declare class SCAUnavailableError extends Error {
code: string;
constructor(message: string);
}
type Correlation = {
correlationId: string;
correlationType: CorrelationTypes;
};
export interface RegistrationDeviceRequest {
relyingPartyName: string;
deviceName: string;
correlation: Correlation;
configuration: ScaConfiguration;
}
interface RegistrationDeviceParameters {
relyingPartyId: string;
originUrl: string;
relyingPartyName: string;
correlation: Correlation;
configuration: ScaConfiguration;
}
export interface StartRegistrationDeviceParameters extends RegistrationDeviceParameters {
deviceName: string;
}
export interface FinishRegistrationDeviceParameters extends RegistrationDeviceParameters {
deviceReference: string;
publicKeyCredential: PublicKeyCredential;
}
export interface PrivilegedRequest {
scaRealm: string;
url: string;
operation: string;
body: BodyInit;
headers: any;
correlationType: CorrelationTypes;
}
export declare class ServerError extends Error {
errorResponse: any;
constructor(errorResponse: any, ...params: any[]);
}
export {};
export declare const removeEmptyJsonElements: (obj: any) => any;
export declare const getBaseUrl: () => string;
export declare const getHostName: () => string;
export declare const base64urlToUint8array: (base64Bytes: any) => Uint8Array;
export declare const uint8arrayToBase64url: (bytes: ArrayBuffer | Uint8Array | null) => string;
export declare const base64ToUint8array: (base64Bytes: any) => Uint8Array;
export declare const uint8arrayToBase64: (bytes: ArrayBuffer | Uint8Array | null) => string;
{
"name": "@adyen/bpscaweb",
"version": "0.0.2",
"version": "0.1.0",
"description": "Balance Platform SCA Web library",

@@ -5,0 +5,0 @@ "license": "MIT",

@@ -1,1 +0,71 @@

# bpscaweb
# Balance Platform SCA Web
This library offers an easy way to perform operations with **Strong Customer Authorization**. This library is based on [**WebAuthn**](https://www.w3.org/TR/webauthn/) to guarantee the security of the operations.
## Installation
You can use this library direclty on your browser or you can add as a dependency on your `JS` project.
With **npm** do
```bash
npm install @adyen/bpscaweb
```
With **browsers** do
```html
<script type="module" src="bpscaweb.es.js"></script>
<script type="module">
import ScaWebauthn from '/js/bpscaweb.es.js';
...
</script>
```
## Configuration
Once you have installed the component, you can configure it when you create a new _handler_.
```js
const handler = ScaWebauthn.create(options);
```
### Options
These are the options you can pass to the component
| Option | Required | Type | Description |
| :---------------: | :--------------------------: | :--------------------------: | :---------------------------------------------- |
| relyingPartyName | Yes | string | Your identifier for the device to be registered |
**Example**: Create a handler
```javascript
const scaWebauthn = ScaWebauthn.create({
relyingPartyName: 'adyen_bpsca',
});
```
## Check availability
Check if SCA is available on the device.
```javascript
const sdkOutput = await scaWebauthn.checkAvailability();
````
## Register device
Exchange the `sdkInput` return by the backend in the initiate register call
```javascript
const sdkOutput = await scaWebauthn.register(sdkInput); // the new output that will be shared with the server to complete the registration
````
## Authenticate device
Exchange the `sdkInput` return by the backend in the first call
```javascript
const sdkOutput = await scaWebauthn.authenticate(sdkInput); // the new output that will be shared with the server to authenticate the call
````
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc