1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
// 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()');
|