135 lines
4.3 KiB
JavaScript
135 lines
4.3 KiB
JavaScript
// META: script=/resources/testdriver.js
|
|
// META: script=/resources/testdriver-vendor.js
|
|
// META: script=/resources/utils.js
|
|
// META: script=helpers.js
|
|
|
|
function assertObjectKeysEq(a, b) {
|
|
let a_keys = new Set(Object.keys(a));
|
|
let b_keys = new Set(Object.keys(b));
|
|
assert_true(
|
|
a_keys.length == b_keys.length && [...a_keys].every(k => b_keys.has(k)),
|
|
`keys differ: ${a_keys} != ${b_keys}`);
|
|
}
|
|
|
|
// Returns the JSON encoding for `value`. If `value` is a function, `optParent`
|
|
// is the object to which execution should be bound.
|
|
function convertValue(value, optParent) {
|
|
switch (typeof value) {
|
|
case 'undefined':
|
|
case 'boolean':
|
|
case 'number':
|
|
case 'bigint':
|
|
case 'string':
|
|
case 'symbol':
|
|
return value;
|
|
case 'function':
|
|
return value.apply(optParent);
|
|
case 'object':
|
|
if (value.__proto__.constructor === Object) {
|
|
var result = {};
|
|
Object.entries(value).map((k, v) => {
|
|
result[k] = convertValue(k, v);
|
|
});
|
|
return result;
|
|
}
|
|
if (value instanceof Array) {
|
|
return value.map(convertValue);
|
|
}
|
|
if (value instanceof ArrayBuffer) {
|
|
return base64urlEncode(new Uint8Array(value));
|
|
}
|
|
throw `can't convert value ${value} in ${parent}`;
|
|
default:
|
|
throw `${value} has unexpected type`;
|
|
}
|
|
}
|
|
|
|
// Conversion spec for a single attribute.
|
|
// @typedef {Object} ConvertParam
|
|
// @property {string} name - The name of the attribute to convert from
|
|
// @property {string=} target - The name of the attribute to convert to, if
|
|
// different from `name`
|
|
// @property {function=} func - Method to convert this property. Defaults to
|
|
// convertValue().
|
|
|
|
// Returns the JSON object for `obj`.
|
|
//
|
|
// @param obj
|
|
// @param {Array<(string|ConvertParam)>} keys - The names of parameters in
|
|
// `obj` to convert, or instances of ConvertParam for complex cases.
|
|
function convertObject(obj, params) {
|
|
let result = {};
|
|
params.forEach((param) => {
|
|
switch (typeof (param)) {
|
|
case 'string':
|
|
assert_true(param in obj, `missing ${param}`);
|
|
if (obj[param] !== null) {
|
|
result[param] = convertValue(obj[param], obj);
|
|
}
|
|
break;
|
|
case 'object':
|
|
assert_true(param.name in obj, `missing ${param.name}`);
|
|
const val = obj[param.name];
|
|
const target_key = param.target || param.name;
|
|
const convert_func = param.func || convertValue;
|
|
try {
|
|
result[target_key] =
|
|
convert_func(((typeof val) == 'function' ? val.apply(obj) : val));
|
|
} catch (e) {
|
|
throw `failed to convert ${param.name}: ${e}`
|
|
}
|
|
break;
|
|
default:
|
|
throw `invalid key ${param}`;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
// Converts an AuthenticatorResponse instance into a JSON object.
|
|
// @param {!AuthenticatorResponse}
|
|
function authenticatorResponseToJson(response) {
|
|
assert_true(
|
|
(response instanceof AuthenticatorAttestationResponse) ||
|
|
(response instanceof AuthenticatorAssertionResponse));
|
|
const isAttestation = (response instanceof AuthenticatorAttestationResponse);
|
|
const keys =
|
|
(isAttestation ?
|
|
[
|
|
'clientDataJSON', 'attestationObject',
|
|
{name: 'getAuthenticatorData', target: 'authenticatorData'},
|
|
{name: 'getPublicKey', target: 'publicKey'},
|
|
{name: 'getPublicKeyAlgorithm', target: 'publicKeyAlgorithm'},
|
|
{name: 'getTransports', target: 'transports'}
|
|
] :
|
|
['clientDataJSON', 'authenticatorData', 'signature', 'userHandle']);
|
|
return convertObject(response, keys);
|
|
}
|
|
|
|
// Converts a PublicKeyCredential instance to a JSON object.
|
|
// @param {!PublicKeyCredential}
|
|
function publicKeyCredentialToJson(cred) {
|
|
const keys = [
|
|
'id', 'rawId', {name: 'response', func: authenticatorResponseToJson},
|
|
'authenticatorAttachment',
|
|
{name: 'getClientExtensionResults', target: 'clientExtensionResults'},
|
|
'type'
|
|
];
|
|
return convertObject(cred, keys);
|
|
}
|
|
|
|
virtualAuthenticatorPromiseTest(
|
|
async t => {
|
|
let credential = await createCredential();
|
|
assertJsonEquals(
|
|
credential.toJSON(), publicKeyCredentialToJson(credential));
|
|
|
|
let assertion = await assertCredential(credential);
|
|
assertJsonEquals(
|
|
assertion.toJSON(), publicKeyCredentialToJson(assertion));
|
|
},
|
|
{
|
|
protocol: 'ctap2_1',
|
|
transport: 'usb',
|
|
},
|
|
'toJSON()');
|