- commit
- 271b7c240a75250fb9337a5a53c1ffffe4328687
- parent
- c1d45f9f973b310f7225a3604e17e6d7a2dfc2ad
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2025-02-03 15:40
js: vendor webauthn-json
Diffstat
| M | README.md | 2 | +- |
| M | mfa/static/mfa/fido2.js | 2 | +- |
| A | mfa/static/mfa/vendor/webauthn-json.browser-ponyfill.js | 243 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 245 insertions, 2 deletions
diff --git a/README.md b/README.md
@@ -29,7 +29,7 @@ pip install django-mfa3 29 29 `settings.py` for a full list of settings. 30 30 4. Register URLs: `path('mfa/', include('mfa.urls', namespace='mfa')` 31 31 5. The included templates are just examples, so you should [replace them](https://docs.djangoproject.com/en/stable/howto/overriding-templates/) with your own32 -1 6. FIDO2 requires client side code. You can either implement it yourself or use the included fido2.js (in which case you will have to provide the third party library [@github/webauthn-json](https://www.npmjs.com/package/@github/webauthn-json)).-1 32 6. FIDO2 requires client side code. You can either implement it yourself or use the included fido2.js. 33 33 7. Somewhere in your app, add a link to `'mfa:list'` 34 34 35 35 ## Enforce MFA
diff --git a/mfa/static/mfa/fido2.js b/mfa/static/mfa/fido2.js
@@ -1,4 +1,4 @@1 -1 import * as webauthnJSON from 'https://cdn.jsdelivr.net/npm/@github/webauthn-json@2.1.1/dist/esm/webauthn-json.browser-ponyfill.js';-1 1 import * as webauthnJSON from './vendor/webauthn-json.browser-ponyfill.js'; 2 2 3 3 var initCreate = function() { 4 4 var form = document.querySelector('form[data-fido2-create]');
diff --git a/mfa/static/mfa/vendor/webauthn-json.browser-ponyfill.js b/mfa/static/mfa/vendor/webauthn-json.browser-ponyfill.js
@@ -0,0 +1,243 @@
-1 1 /*!
-1 2 * @github/webauthn-json 2.1.1
-1 3 * Copyright (c) 2019 GitHub, Inc.
-1 4 *
-1 5 * Permission is hereby granted, free of charge, to any person obtaining a copy
-1 6 * of this software and associated documentation files (the "Software"), to
-1 7 * deal in the Software without restriction, including without limitation the
-1 8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-1 9 * sell copies of the Software, and to permit persons to whom the Software is
-1 10 * furnished to do so, subject to the following conditions:
-1 11 *
-1 12 * The above copyright notice and this permission notice shall be included in
-1 13 * all copies or substantial portions of the Software.
-1 14 *
-1 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-1 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-1 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-1 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-1 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-1 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-1 21 * IN THE SOFTWARE.
-1 22 */
-1 23
-1 24 // src/webauthn-json/base64url.ts
-1 25 function base64urlToBuffer(baseurl64String) {
-1 26 const padding = "==".slice(0, (4 - baseurl64String.length % 4) % 4);
-1 27 const base64String = baseurl64String.replace(/-/g, "+").replace(/_/g, "/") + padding;
-1 28 const str = atob(base64String);
-1 29 const buffer = new ArrayBuffer(str.length);
-1 30 const byteView = new Uint8Array(buffer);
-1 31 for (let i = 0; i < str.length; i++) {
-1 32 byteView[i] = str.charCodeAt(i);
-1 33 }
-1 34 return buffer;
-1 35 }
-1 36 function bufferToBase64url(buffer) {
-1 37 const byteView = new Uint8Array(buffer);
-1 38 let str = "";
-1 39 for (const charCode of byteView) {
-1 40 str += String.fromCharCode(charCode);
-1 41 }
-1 42 const base64String = btoa(str);
-1 43 const base64urlString = base64String.replace(/\+/g, "-").replace(
-1 44 /\//g,
-1 45 "_"
-1 46 ).replace(/=/g, "");
-1 47 return base64urlString;
-1 48 }
-1 49
-1 50 // src/webauthn-json/convert.ts
-1 51 var copyValue = "copy";
-1 52 var convertValue = "convert";
-1 53 function convert(conversionFn, schema, input) {
-1 54 if (schema === copyValue) {
-1 55 return input;
-1 56 }
-1 57 if (schema === convertValue) {
-1 58 return conversionFn(input);
-1 59 }
-1 60 if (schema instanceof Array) {
-1 61 return input.map((v) => convert(conversionFn, schema[0], v));
-1 62 }
-1 63 if (schema instanceof Object) {
-1 64 const output = {};
-1 65 for (const [key, schemaField] of Object.entries(schema)) {
-1 66 if (schemaField.derive) {
-1 67 const v = schemaField.derive(input);
-1 68 if (v !== void 0) {
-1 69 input[key] = v;
-1 70 }
-1 71 }
-1 72 if (!(key in input)) {
-1 73 if (schemaField.required) {
-1 74 throw new Error(`Missing key: ${key}`);
-1 75 }
-1 76 continue;
-1 77 }
-1 78 if (input[key] == null) {
-1 79 output[key] = null;
-1 80 continue;
-1 81 }
-1 82 output[key] = convert(
-1 83 conversionFn,
-1 84 schemaField.schema,
-1 85 input[key]
-1 86 );
-1 87 }
-1 88 return output;
-1 89 }
-1 90 }
-1 91 function derived(schema, derive) {
-1 92 return {
-1 93 required: true,
-1 94 schema,
-1 95 derive
-1 96 };
-1 97 }
-1 98 function required(schema) {
-1 99 return {
-1 100 required: true,
-1 101 schema
-1 102 };
-1 103 }
-1 104 function optional(schema) {
-1 105 return {
-1 106 required: false,
-1 107 schema
-1 108 };
-1 109 }
-1 110
-1 111 // src/webauthn-json/basic/schema.ts
-1 112 var publicKeyCredentialDescriptorSchema = {
-1 113 type: required(copyValue),
-1 114 id: required(convertValue),
-1 115 transports: optional(copyValue)
-1 116 };
-1 117 var simplifiedExtensionsSchema = {
-1 118 appid: optional(copyValue),
-1 119 appidExclude: optional(copyValue),
-1 120 credProps: optional(copyValue)
-1 121 };
-1 122 var simplifiedClientExtensionResultsSchema = {
-1 123 appid: optional(copyValue),
-1 124 appidExclude: optional(copyValue),
-1 125 credProps: optional(copyValue)
-1 126 };
-1 127 var credentialCreationOptions = {
-1 128 publicKey: required({
-1 129 rp: required(copyValue),
-1 130 user: required({
-1 131 id: required(convertValue),
-1 132 name: required(copyValue),
-1 133 displayName: required(copyValue)
-1 134 }),
-1 135 challenge: required(convertValue),
-1 136 pubKeyCredParams: required(copyValue),
-1 137 timeout: optional(copyValue),
-1 138 excludeCredentials: optional([publicKeyCredentialDescriptorSchema]),
-1 139 authenticatorSelection: optional(copyValue),
-1 140 attestation: optional(copyValue),
-1 141 extensions: optional(simplifiedExtensionsSchema)
-1 142 }),
-1 143 signal: optional(copyValue)
-1 144 };
-1 145 var publicKeyCredentialWithAttestation = {
-1 146 type: required(copyValue),
-1 147 id: required(copyValue),
-1 148 rawId: required(convertValue),
-1 149 authenticatorAttachment: optional(copyValue),
-1 150 response: required({
-1 151 clientDataJSON: required(convertValue),
-1 152 attestationObject: required(convertValue),
-1 153 transports: derived(
-1 154 copyValue,
-1 155 (response) => {
-1 156 var _a;
-1 157 return ((_a = response.getTransports) == null ? void 0 : _a.call(response)) || [];
-1 158 }
-1 159 )
-1 160 }),
-1 161 clientExtensionResults: derived(
-1 162 simplifiedClientExtensionResultsSchema,
-1 163 (pkc) => pkc.getClientExtensionResults()
-1 164 )
-1 165 };
-1 166 var credentialRequestOptions = {
-1 167 mediation: optional(copyValue),
-1 168 publicKey: required({
-1 169 challenge: required(convertValue),
-1 170 timeout: optional(copyValue),
-1 171 rpId: optional(copyValue),
-1 172 allowCredentials: optional([publicKeyCredentialDescriptorSchema]),
-1 173 userVerification: optional(copyValue),
-1 174 extensions: optional(simplifiedExtensionsSchema)
-1 175 }),
-1 176 signal: optional(copyValue)
-1 177 };
-1 178 var publicKeyCredentialWithAssertion = {
-1 179 type: required(copyValue),
-1 180 id: required(copyValue),
-1 181 rawId: required(convertValue),
-1 182 authenticatorAttachment: optional(copyValue),
-1 183 response: required({
-1 184 clientDataJSON: required(convertValue),
-1 185 authenticatorData: required(convertValue),
-1 186 signature: required(convertValue),
-1 187 userHandle: required(convertValue)
-1 188 }),
-1 189 clientExtensionResults: derived(
-1 190 simplifiedClientExtensionResultsSchema,
-1 191 (pkc) => pkc.getClientExtensionResults()
-1 192 )
-1 193 };
-1 194
-1 195 // src/webauthn-json/basic/api.ts
-1 196 function createRequestFromJSON(requestJSON) {
-1 197 return convert(base64urlToBuffer, credentialCreationOptions, requestJSON);
-1 198 }
-1 199 function createResponseToJSON(credential) {
-1 200 return convert(
-1 201 bufferToBase64url,
-1 202 publicKeyCredentialWithAttestation,
-1 203 credential
-1 204 );
-1 205 }
-1 206 function getRequestFromJSON(requestJSON) {
-1 207 return convert(base64urlToBuffer, credentialRequestOptions, requestJSON);
-1 208 }
-1 209 function getResponseToJSON(credential) {
-1 210 return convert(
-1 211 bufferToBase64url,
-1 212 publicKeyCredentialWithAssertion,
-1 213 credential
-1 214 );
-1 215 }
-1 216
-1 217 // src/webauthn-json/basic/supported.ts
-1 218 function supported() {
-1 219 return !!(navigator.credentials && navigator.credentials.create && navigator.credentials.get && window.PublicKeyCredential);
-1 220 }
-1 221
-1 222 // src/webauthn-json/browser-ponyfill.ts
-1 223 async function create(options) {
-1 224 const response = await navigator.credentials.create(
-1 225 options
-1 226 );
-1 227 response.toJSON = () => createResponseToJSON(response);
-1 228 return response;
-1 229 }
-1 230 async function get(options) {
-1 231 const response = await navigator.credentials.get(
-1 232 options
-1 233 );
-1 234 response.toJSON = () => getResponseToJSON(response);
-1 235 return response;
-1 236 }
-1 237 export {
-1 238 create,
-1 239 get,
-1 240 createRequestFromJSON as parseCreationOptionsFromJSON,
-1 241 getRequestFromJSON as parseRequestOptionsFromJSON,
-1 242 supported
-1 243 };