django-mfa3

multi factor authentication for django
git clone https://git.ce9e.org/django-mfa3.git

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 own
   32    -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 };