github.com/greenpau/go-authcrunch@v1.1.4/assets/portal/templates/basic/settings.template (about) 1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <title>{{ .MetaTitle }} - {{ .PageTitle }}</title> 5 <!-- Required meta tags --> 6 <meta charset="utf-8"> 7 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 8 <meta name="description" content="{{ .MetaDescription }}" /> 9 <meta name="author" content="{{ .MetaAuthor }}" /> 10 <link rel="shortcut icon" href="{{ pathjoin .ActionEndpoint "/assets/images/favicon.png" }}" type="image/png"> 11 <link rel="icon" href="{{ pathjoin .ActionEndpoint "/assets/images/favicon.png" }}" type="image/png"> 12 13 <!-- Matrialize CSS --> 14 <link rel="stylesheet" href="{{ pathjoin .ActionEndpoint "/assets/materialize-css/css/materialize.css" }}" /> 15 <link rel="stylesheet" href="{{ pathjoin .ActionEndpoint "/assets/google-webfonts/roboto.css" }}" /> 16 {{ if or (eq .Data.view "mfa-add-app") (eq .Data.view "mfa-test-app") }} 17 <link rel="stylesheet" href="{{ pathjoin .ActionEndpoint "/assets/google-webfonts/montserrat.css" }}" /> 18 {{ end }} 19 <link rel="stylesheet" href="{{ pathjoin .ActionEndpoint "/assets/line-awesome/line-awesome.css" }}" /> 20 {{ if or (eq .Data.view "sshkeys-add") (eq .Data.view "gpgkeys-add") (eq .Data.view "sshkeys-view") (eq .Data.view "gpgkeys-view") }} 21 <link rel="stylesheet" href="{{ pathjoin .ActionEndpoint "/assets/highlight.js/css/atom-one-dark.min.css" }}" /> 22 {{ end }} 23 {{ if or (eq .Data.view "apikeys-add") (eq .Data.view "apikeys-add-status") }} 24 <link rel="stylesheet" href="{{ pathjoin .ActionEndpoint "/assets/highlight.js/css/atom-one-dark.min.css" }}" /> 25 {{ end }} 26 <link rel="stylesheet" href="{{ pathjoin .ActionEndpoint "/assets/css/styles.css" }}" /> 27 {{ if eq .Data.ui_options.custom_css_required "yes" }} 28 <link rel="stylesheet" href="{{ pathjoin .ActionEndpoint "/assets/css/custom.css" }}" /> 29 {{ end }} 30 {{ if or (eq .Data.view "mfa-add-app") (eq .Data.view "mfa-test-app") }} 31 <link rel="stylesheet" href="{{ pathjoin .ActionEndpoint "/assets/css/mfa_app.css" }}" /> 32 {{ end }} 33 </head> 34 <body class="app-body"> 35 <div class="container app-container"> 36 <div class="row"> 37 <nav> 38 <div class="nav-wrapper"> 39 {{ if .LogoURL }} 40 <img src="{{ .LogoURL }}" alt="{{ .LogoDescription }}" /> 41 {{ end }} 42 <a href="#" class="brand-logo">{{ .PageTitle }}</a> 43 <ul id="nav-mobile" class="right hide-on-med-and-down"> 44 <li> 45 <a href="{{ pathjoin .ActionEndpoint "/portal" }}"> 46 <button type="button" class="btn waves-effect waves-light navbtn active"> 47 <span class="app-btn-text">Portal</span> 48 <i class="las la-home left app-btn-icon app-navbar-btn-icon"></i> 49 </button> 50 </a> 51 </li> 52 <li> 53 <a href="{{ pathjoin .ActionEndpoint "/logout" }}" class="navbtn-last"> 54 <button type="button" class="btn waves-effect waves-light navbtn active navbtn-last"> 55 <span class="app-btn-text">Logout</span> 56 <i class="las la-sign-out-alt left app-btn-icon app-navbar-btn-icon"></i> 57 </button> 58 </a> 59 </li> 60 </ul> 61 </div> 62 </nav> 63 </div> 64 <div class="row"> 65 <div class="col s12 l3"> 66 <div class="collection"> 67 <a href="{{ pathjoin .ActionEndpoint "/settings/" }}" class="collection-item{{ if eq .Data.view "general" }} active{{ end }}">General</a> 68 <a href="{{ pathjoin .ActionEndpoint "/settings/sshkeys" }}" class="collection-item{{ if eq .Data.view "sshkeys" }} active{{ end }}">SSH Keys</a> 69 <a href="{{ pathjoin .ActionEndpoint "/settings/gpgkeys" }}" class="collection-item{{ if eq .Data.view "gpgkeys" }} active{{ end }}">GPG Keys</a> 70 <a href="{{ pathjoin .ActionEndpoint "/settings/apikeys" }}" class="collection-item{{ if eq .Data.view "apikeys" }} active{{ end }}">API Keys</a> 71 <a href="{{ pathjoin .ActionEndpoint "/settings/mfa" }}" class="collection-item{{ if eq .Data.view "mfa" }} active{{ end }}">MFA</a> 72 <a href="{{ pathjoin .ActionEndpoint "/settings/password" }}" class="collection-item{{ if eq .Data.view "password" }} active{{ end }}">Password</a> 73 <a href="{{ pathjoin .ActionEndpoint "/settings/connected" }}" class="collection-item{{ if eq .Data.view "connected" }} active{{ end }}">Connected Accounts</a> 74 <a href="{{ pathjoin .ActionEndpoint "/portal" }}" class="hide-on-med-and-up collection-item">Portal</a> 75 <a href="{{ pathjoin .ActionEndpoint "/logout" }}" class="hide-on-med-and-up collection-item">Logout</a> 76 </div> 77 </div> 78 <div class="col s12 l9 app-content"> 79 {{ if eq .Data.view "general" }} 80 <div class="row"> 81 <div class="col s12"> 82 {{ if eq .Data.status "SUCCESS" }} 83 <p> 84 <b>ID</b>: {{ .Data.metadata.ID }}<br/> 85 {{ if .Data.metadata.Name }}<b>Name</b>: {{ .Data.metadata.Name }}<br/>{{ end }} 86 {{ if .Data.metadata.Title }}<b>Title</b>: {{ .Data.metadata.Title }}<br/>{{ end }} 87 <b>Username</b>: {{ .Data.metadata.Username }}<br/> 88 <b>Email</b>: {{ .Data.metadata.Email }}<br/> 89 <b>Created</b>: {{ .Data.metadata.Created }}<br/> 90 <b>LastModified</b>: {{ .Data.metadata.LastModified }}<br/> 91 <b>Revision</b>: {{ .Data.metadata.Revision }} 92 </p> 93 {{ else }} 94 <p>{{.Data.status }}: {{ .Data.status_reason }}</p> 95 {{ end }} 96 </div> 97 </div> 98 {{ end }} 99 {{ if eq .Data.view "sshkeys" }} 100 <div class="row right"> 101 <div class="col s12 right"> 102 <a href="{{ pathjoin .ActionEndpoint "/settings/sshkeys/add" }}"> 103 <button type="button" class="btn waves-effect waves-light navbtn active app-btn"> 104 <i class="las la-key left app-btn-icon"></i> 105 <span class="app-btn-text">Add SSH Key</span> 106 </button> 107 </a> 108 </div> 109 </div> 110 <div class="row"> 111 <div class="col s12"> 112 {{ if .Data.sshkeys }} 113 {{range .Data.sshkeys}} 114 <div class="card"> 115 <div class="card-content"> 116 <span class="card-title">{{ .Comment }}</span> 117 <p> 118 <b>ID</b>: {{ .ID }}<br/> 119 <b>Type:</b> {{ .Type }}<br/> 120 <b>Fingerprint (SHA256)</b>: {{ .Fingerprint }}<br/> 121 <b>Fingerprint (MD5)</b>: {{ .FingerprintMD5 }}<br/> 122 <b>Created At</b>: {{ .CreatedAt }} 123 </p> 124 </div> 125 <div class="card-action"> 126 <a href="{{ pathjoin $.ActionEndpoint "/settings/sshkeys/delete" .ID }}">Delete</a> 127 <a href="{{ pathjoin $.ActionEndpoint "/settings/sshkeys/view" .ID }}">View</a> 128 </div> 129 </div> 130 {{ end }} 131 {{ else }} 132 <p>No registered SSH Keys found</p> 133 {{ end }} 134 </div> 135 </div> 136 {{ end }} 137 {{ if eq .Data.view "sshkeys-add" }} 138 <form action="{{ pathjoin .ActionEndpoint "/settings/sshkeys/add" }}" method="POST"> 139 <div class="row"> 140 <div class="col s12"> 141 <h1>Add SSH Key</h1> 142 <p>Please paste your public SSH key here.</p> 143 <div class="input-field shell-textarea-wrapper"> 144 <textarea id="key1" name="key1" class="hljs shell-textarea"></textarea> 145 </div> 146 <div class="input-field"> 147 <input placeholder="Comment" name="comment1" id="comment1" type="text" autocorrect="off" autocapitalize="off" autocomplete="off" class="validate"> 148 </div> 149 <div class="right"> 150 <button type="submit" name="submit" class="btn waves-effect waves-light navbtn active navbtn-last app-btn"> 151 <i class="las la-plus-circle left app-btn-icon"></i> 152 <span class="app-btn-text">Add SSH Key</span> 153 </button> 154 </div> 155 </div> 156 </div> 157 </form> 158 {{ end }} 159 {{ if eq .Data.view "sshkeys-add-status" }} 160 <div class="row"> 161 <div class="col s12"> 162 {{ if eq .Data.status "SUCCESS" }} 163 <h1>Public SSH Key</h1> 164 <p>{{ .Data.status_reason }}</p> 165 <a href="{{ pathjoin .ActionEndpoint "/settings/sshkeys" }}"> 166 <button type="button" class="btn waves-effect waves-light navbtn active"> 167 <i class="las la-undo-alt left app-btn-icon"></i> 168 <span class="app-btn-text">Go Back</span> 169 </button> 170 </a> 171 {{ else }} 172 <h1>Public SSH Key</h1> 173 <p>Reason: {{ .Data.status_reason }} </p> 174 <a href="{{ pathjoin .ActionEndpoint "/settings/sshkeys/add" }}"> 175 <button type="button" class="btn waves-effect waves-light navbtn active"> 176 <i class="las la-undo-alt left app-btn-icon"></i> 177 <span class="app-btn-text">Try Again</span> 178 </button> 179 </a> 180 {{ end }} 181 </div> 182 </div> 183 {{ end }} 184 {{ if eq .Data.view "sshkeys-delete-status" }} 185 <div class="row"> 186 <div class="col s12"> 187 <h1>Public SSH Key</h1> 188 <p>{{.Data.status }}: {{ .Data.status_reason }}</p> 189 <a href="{{ pathjoin .ActionEndpoint "/settings/sshkeys" }}"> 190 <button type="button" class="btn waves-effect waves-light navbtn active"> 191 <i class="las la-undo-alt left app-btn-icon"></i> 192 <span class="app-btn-text">Go Back</span> 193 </button> 194 </a> 195 </div> 196 </div> 197 {{ end }} 198 {{ if eq .Data.view "gpgkeys" }} 199 <div class="row right"> 200 <div class="col s12 right"> 201 <a href="{{ pathjoin .ActionEndpoint "/settings/gpgkeys/add" }}"> 202 <button type="button" class="btn waves-effect waves-light navbtn active app-btn"> 203 <i class="las la-key left app-btn-icon"></i> 204 <span class="app-btn-text">Add GPG Key</span> 205 </button> 206 </a> 207 </div> 208 </div> 209 <div class="row"> 210 <div class="col s12"> 211 {{ if .Data.gpgkeys }} 212 {{range .Data.gpgkeys}} 213 <div class="card"> 214 <div class="card-content"> 215 <span class="card-title">{{ .Comment }}</span> 216 <p> 217 <b>ID</b>: {{ .ID }}<br/> 218 <b>Usage:</b> {{ .Usage }}<br/> 219 <b>Type:</b> {{ .Type }}<br/> 220 <b>Fingerprint</b>: {{ .Fingerprint }}<br/> 221 <b>Created At</b>: {{ .CreatedAt }} 222 </p> 223 </div> 224 <div class="card-action"> 225 <a href="{{ pathjoin $.ActionEndpoint "/settings/gpgkeys/delete" .ID }}">Delete</a> 226 <a href="{{ pathjoin $.ActionEndpoint "/settings/gpgkeys/view" .ID }}">View</a> 227 </div> 228 </div> 229 {{ end }} 230 {{ else }} 231 <p>No registered GPG Keys found</p> 232 {{ end }} 233 </div> 234 </div> 235 {{ end }} 236 {{ if eq .Data.view "gpgkeys-add" }} 237 <form action="{{ pathjoin .ActionEndpoint "/settings/gpgkeys/add" }}" method="POST"> 238 <div class="row"> 239 <div class="col s12"> 240 <h1>Add GPG Key</h1> 241 <p>Please paste your public GPG key here.</p> 242 <div class="input-field shell-textarea-wrapper"> 243 <textarea id="key1" name="key1" class="hljs shell-textarea"></textarea> 244 </div> 245 <div class="input-field"> 246 <input placeholder="Comment" name="comment1" id="comment1" type="text" autocorrect="off" autocapitalize="off" autocomplete="off" class="validate"> 247 </div> 248 <div class="right"> 249 <button type="submit" name="submit" class="btn waves-effect waves-light navbtn active navbtn-last app-btn"> 250 <i class="las la-plus-circle left app-btn-icon"></i> 251 <span class="app-btn-text">Add GPG Key</span> 252 </button> 253 </div> 254 </div> 255 </div> 256 </form> 257 {{ end }} 258 {{ if eq .Data.view "gpgkeys-add-status" }} 259 <div class="row"> 260 <div class="col s12"> 261 {{ if eq .Data.status "SUCCESS" }} 262 <h1>Public GPG Key</h1> 263 <p>{{ .Data.status_reason }}</p> 264 <a href="{{ pathjoin .ActionEndpoint "/settings/gpgkeys" }}"> 265 <button type="button" class="btn waves-effect waves-light navbtn active"> 266 <i class="las la-undo-alt left app-btn-icon"></i> 267 <span class="app-btn-text">Go Back</span> 268 </button> 269 </a> 270 {{ else }} 271 <h1>Public GPG Key</h1> 272 <p>Reason: {{ .Data.status_reason }} </p> 273 <a href="{{ pathjoin .ActionEndpoint "/settings/gpgkeys/add" }}"> 274 <button type="button" class="btn waves-effect waves-light navbtn active"> 275 <i class="las la-undo-alt left app-btn-icon"></i> 276 <span class="app-btn-text">Try Again</span> 277 </button> 278 </a> 279 {{ end }} 280 </div> 281 </div> 282 {{ end }} 283 {{ if eq .Data.view "gpgkeys-delete-status" }} 284 <div class="row"> 285 <div class="col s12"> 286 <h1>Public GPG Key</h1> 287 <p>{{.Data.status }}: {{ .Data.status_reason }}</p> 288 <a href="{{ pathjoin .ActionEndpoint "/settings/gpgkeys" }}"> 289 <button type="button" class="btn waves-effect waves-light navbtn active"> 290 <i class="las la-undo-alt left app-btn-icon"></i> 291 <span class="app-btn-text">Go Back</span> 292 </button> 293 </a> 294 </div> 295 </div> 296 {{ end }} 297 {{ if or (eq .Data.view "sshkeys-view") (eq .Data.view "gpgkeys-view") }} 298 <div class="row"> 299 <div class="col s12"> 300 {{ if eq .Data.view "gpgkeys-view" }} 301 <h1>GPG Key</h1> 302 {{ else }} 303 <h1>SSH Key</h1> 304 {{ end }} 305 <pre><code class="language-json hljs">{{ .Data.key }}</code></pre> 306 {{ if .Data.pem_key }} 307 <h5>PEM</h5> 308 <pre><code class="language-text hljs">{{ .Data.pem_key }}</code></pre> 309 {{ end }} 310 {{ if .Data.openssh_key }} 311 <h5>OpenSSH</h5> 312 <pre><code class="language-text hljs">{{ .Data.openssh_key }}</code></pre> 313 {{ end }} 314 {{ if eq .Data.view "gpgkeys-view" }} 315 <a href="{{ pathjoin .ActionEndpoint "/settings/gpgkeys" }}"> 316 {{ else }} 317 <a href="{{ pathjoin .ActionEndpoint "/settings/sshkeys" }}"> 318 {{ end }} 319 <button type="button" class="btn waves-effect waves-light navbtn active"> 320 <i class="las la-undo-alt left app-btn-icon"></i> 321 <span class="app-btn-text">Go Back</span> 322 </button> 323 </a> 324 </div> 325 </div> 326 {{ end }} 327 {{ if eq .Data.view "apikeys" }} 328 <div class="row right"> 329 <div class="col s12 right"> 330 <a href="{{ pathjoin .ActionEndpoint "/settings/apikeys/add" }}"> 331 <button type="button" class="btn waves-effect waves-light navbtn active app-btn"> 332 <i class="las la-key left app-btn-icon"></i> 333 <span class="app-btn-text">Add API Key</span> 334 </button> 335 </a> 336 </div> 337 </div> 338 <div class="row"> 339 <div class="col s12"> 340 {{ if .Data.apikeys }} 341 {{range .Data.apikeys}} 342 <div class="card"> 343 <div class="card-content"> 344 <span class="card-title">{{ .Comment }}</span> 345 <p> 346 <b>ID</b>: {{ .ID }}<br/> 347 <b>Created At</b>: {{ .CreatedAt }} 348 </p> 349 </div> 350 <div class="card-action"> 351 <a href="{{ pathjoin $.ActionEndpoint "/settings/apikeys/delete" .ID }}">Delete</a> 352 </div> 353 </div> 354 {{ end }} 355 {{ else }} 356 <p>No registered API Keys found</p> 357 {{ end }} 358 </div> 359 </div> 360 {{ end }} 361 {{ if eq .Data.view "apikeys-add" }} 362 <form action="{{ pathjoin .ActionEndpoint "/settings/apikeys/add" }}" method="POST"> 363 <div class="row"> 364 <div class="col s12"> 365 <h1>Add API Key</h1> 366 <p>Please provide a nickname to identify your new API key.</p> 367 <div class="input-field"> 368 <input placeholder="Comment" name="comment1" id="comment1" type="text" autocorrect="off" autocapitalize="off" autocomplete="off" class="validate"> 369 </div> 370 <div class="right"> 371 <button type="submit" name="submit" class="btn waves-effect waves-light navbtn active navbtn-last app-btn"> 372 <i class="las la-plus-circle left app-btn-icon"></i> 373 <span class="app-btn-text">Add API Key</span> 374 </button> 375 </div> 376 </div> 377 </div> 378 </form> 379 {{ end }} 380 {{ if eq .Data.view "apikeys-add-status" }} 381 <div class="row"> 382 <div class="col s12"> 383 <h1>API Key</h1> 384 {{ if eq .Data.status "SUCCESS" }} 385 <p>Keep this key secret!</p> 386 <pre><code class="language-text hljs">{{ .Data.api_key }}</code></pre> 387 {{ else }} 388 <p>{{.Data.status }}: {{ .Data.status_reason }}</p> 389 {{ end }} 390 <a href="{{ pathjoin .ActionEndpoint "/settings/apikeys" }}"> 391 <button type="button" class="btn waves-effect waves-light navbtn active"> 392 <i class="las la-undo-alt left app-btn-icon"></i> 393 <span class="app-btn-text">Go Back</span> 394 </button> 395 </a> 396 </div> 397 </div> 398 {{ end }} 399 {{ if eq .Data.view "apikeys-delete-status" }} 400 <div class="row"> 401 <div class="col s12"> 402 <h1>API Key</h1> 403 <p>{{.Data.status }}: {{ .Data.status_reason }}</p> 404 <a href="{{ pathjoin .ActionEndpoint "/settings/apikeys" }}"> 405 <button type="button" class="btn waves-effect waves-light navbtn active"> 406 <i class="las la-undo-alt left app-btn-icon"></i> 407 <span class="app-btn-text">Go Back</span> 408 </button> 409 </a> 410 </div> 411 </div> 412 {{ end }} 413 414 415 {{ if eq .Data.view "mfa" }} 416 <div class="row right"> 417 <div class="col s12 right"> 418 <a href="{{ pathjoin .ActionEndpoint "/settings/mfa/add/app" }}"> 419 <button type="button" class="btn waves-effect waves-light navbtn active app-btn"> 420 <i class="las la-mobile-alt left app-btn-icon"></i> 421 <span class="app-btn-text">Add MFA App</span> 422 </button> 423 </a> 424 <a href="{{ pathjoin .ActionEndpoint "/settings/mfa/add/u2f" }}" class="navbtn-last"> 425 <button type="button" class="btn waves-effect waves-light navbtn active navbtn-last app-btn"> 426 <i class="las la-key left app-btn-icon"></i> 427 <span class="app-btn-text">Add U2F Key</span> 428 </button> 429 </a> 430 </div> 431 </div> 432 <div class="row"> 433 <div class="col s12"> 434 {{ if .Data.mfa_tokens }} 435 {{range .Data.mfa_tokens}} 436 <div class="card"> 437 <div class="card-content"> 438 <span class="card-title">{{ .Comment }}</span> 439 <p> 440 <b>ID</b>: {{ .ID }}<br/> 441 {{ if eq .Type "u2f" }} 442 <b>Type</b>: Hardware/U2F Token<br/> 443 {{ else }} 444 <b>Type</b>: Authenticator App<br/> 445 <b>Algorithm</b>: {{ .Algorithm }}<br/> 446 <b>Period</b>: {{ .Period }} seconds<br/> 447 <b>Digits</b>: {{ .Digits }}<br/> 448 {{ end }} 449 <b>Created At</b>: {{ .CreatedAt }} 450 </p> 451 </div> 452 <div class="card-action"> 453 <a href="{{ pathjoin $.ActionEndpoint "/settings/mfa/delete/" .ID }}">Delete</a> 454 {{ if eq .Type "totp" }} 455 <a href="{{ pathjoin $.ActionEndpoint "/settings/mfa/test/app/" (printf "%d" .Digits) .ID }}">Test</a> 456 {{ end }} 457 {{ if eq .Type "u2f" }} 458 <a href="{{ pathjoin $.ActionEndpoint "/settings/mfa/test/u2f/generic" .ID }}">Test</a> 459 {{ end }} 460 </div> 461 </div> 462 {{ end }} 463 {{ else }} 464 <p>No registered MFA devices found</p> 465 {{ end }} 466 </div> 467 </div> 468 {{ end }} 469 {{ if eq .Data.view "mfa-add-app" }} 470 <form id="mfa-add-app-form" action="{{ pathjoin .ActionEndpoint "/settings/mfa/add/app" }}" method="POST"> 471 <div class="row"> 472 <h1>Add MFA Authenticator Application</h1> 473 <div class="col s12 m11 l11"> 474 <div id="token-params"> 475 <h6 id="token-params-mode" class="hide">Token Parameters</h6> 476 <p><b>Step 1</b>: Amend the label and comment associated with the authenticator. 477 The label is what you would see in your authenticator app. 478 The comment is what you would see in this portal. 479 </p> 480 <div class="input-field"> 481 <input id="label" name="label" type="text" class="validate" pattern="[A-Za-z0-9 -]{4,25}" 482 title="Authentication code should contain 4-25 characters and consists of A-Z, a-z, 0-9, space, and dash characters." 483 maxlength="25" 484 autocorrect="off" autocapitalize="off" autocomplete="off" 485 value="{{ .Data.mfa_label }}" 486 required /> 487 <label for="label">Label</label> 488 </div> 489 <div class="input-field"> 490 <input id="comment" name="comment" type="text" class="validate" pattern="[A-Za-z0-9 -]{4,25}" 491 title="Authentication code should contain 4-25 characters and consists of A-Z, a-z, 0-9, space, and dash characters." 492 maxlength="25" 493 autocorrect="off" autocapitalize="off" autocomplete="off" 494 value="{{ .Data.mfa_comment }}" 495 required /> 496 <label for="comment">Comment</label> 497 </div> 498 <p><b>Step 1a</b> (<i>optional</i>): If necessary, click 499 <a href="#advanced-setup-mode" onclick="toggleAdvancedSetupMode()">here</a> to customize default values. 500 </p> 501 <div id="advanced-setup-all" class="hide"> 502 <h6 id="advanced-setup-mode" class="hide">Advanced Setup Mode</h6> 503 <div id="advanced-setup-secret" class="input-field"> 504 <input id="secret" name="secret" type="text" class="validate" pattern="[A-Za-z0-9]{10,100}" 505 title="Token secret should contain 10-200 characters and consists of A-Z and 0-9 characters only." 506 autocorrect="off" autocapitalize="off" autocomplete="off" 507 maxlength="100" 508 value="{{ .Data.mfa_secret }}" 509 required /> 510 <label for="secret">Token Secret</label> 511 </div> 512 <div id="advanced-setup-period" class="input-field"> 513 <select id="period" name="period" class="browser-default"> 514 <option value="15" {{ if eq .Data.mfa_period "15" }} selected{{ end }}>15 Seconds Lifetime</option> 515 <option value="30" {{ if eq .Data.mfa_period "30" }} selected{{ end }}>30 Seconds Lifetime</option> 516 <option value="60" {{ if eq .Data.mfa_period "60" }} selected{{ end }}>60 Seconds Lifetime</option> 517 <option value="90" {{ if eq .Data.mfa_period "90" }} selected{{ end }}>90 Seconds Lifetime</option> 518 </select> 519 </div> 520 <div id="advanced-setup-digits" class="input-field"> 521 <select id="digits" name="digits" class="browser-default"> 522 <option value="4" {{ if eq .Data.mfa_digits "4" }} selected{{ end }}>4 Digit Code</option> 523 <option value="6" {{ if eq .Data.mfa_digits "6" }} selected{{ end }}>6 Digit Code</option> 524 <option value="8" {{ if eq .Data.mfa_digits "8" }} selected{{ end }}>8 Digit Code</option> 525 </select> 526 </div> 527 </div> 528 <p><b>Step 2</b>: Open your MFA authenticator application, e.g. Microsoft/Google Authenticator, Authy, etc., 529 add new entry and click the "Get QR" link. 530 </p> 531 <div id="mfa-get-qr-code" class="center-align"> 532 <a href="#qr-code-mode" onclick="getQRCode()">Get QR Code</a> 533 </div> 534 </div> 535 <div id="mfa-qr-code" class="hide"> 536 <h6 id="qr-code-mode" class="hide">QR Code Mode</h6> 537 <div class="center-align"> 538 <p>» Scan the QR code image.</p> 539 </div> 540 <div id="mfa-qr-code-image" class="center-align"> 541 <img src="{{ pathjoin .ActionEndpoint "/settings/mfa/barcode/" .Data.code_uri_encoded }}.png" alt="QR Code" /> 542 </div> 543 <div class="center-align"> 544 <p>» Can't scan? Click or copy the link below.</p> 545 </div> 546 <div id="mfa-no-camera-link" class="center-align"> 547 <a href="{{ .Data.code_uri }}">No Camera Link</a> 548 </div> 549 <p><b>Step 3</b>: Enter the authentication code you see in the app and click "Add".</p> 550 <div class="input-field mfa-app-auth-ctrl mfa-app-auth-form"> 551 <input class="mfa-app-auth-passcode" id="passcode" name="passcode" type="text" class="validate" pattern="[0-9]{4,8}" 552 title="Authentication code should contain 4-8 characters and consists of 0-9 characters." 553 autocorrect="off" autocapitalize="off" autocomplete="off" 554 placeholder="______" 555 required /> 556 </div> 557 <input id="email" name="email" type="hidden" value="{{ .Data.mfa_email }}" /> 558 <input id="type" name="type" type="hidden" value="{{ .Data.mfa_type }}" /> 559 <input id="barcode_uri" name "barcode_uri" type="hidden" value="{{ pathjoin .ActionEndpoint "/settings/mfa/barcode/"}}" /> 560 <div class="row right"> 561 <button type="submit" name="submit" class="btn waves-effect waves-light navbtn active navbtn-last app-btn"> 562 <i class="las la-plus-circle left app-btn-icon"></i> 563 <span class="app-btn-text">Add</span> 564 </button> 565 </div> 566 </div> 567 </div> 568 </div> 569 </form> 570 {{ end }} 571 {{ if eq .Data.view "mfa-add-app-status" }} 572 <div class="row"> 573 <div class="col s12"> 574 <h1>MFA Token</h1> 575 <p>{{.Data.status }}: {{ .Data.status_reason }}</p> 576 {{ if eq .Data.status "SUCCESS" }} 577 <a href="{{ pathjoin .ActionEndpoint "/settings/mfa" }}"> 578 <button type="button" class="btn waves-effect waves-light navbtn active"> 579 <i class="las la-undo-alt left app-btn-icon"></i> 580 <span class="app-btn-text">Go Back</span> 581 </button> 582 </a> 583 {{ else }} 584 <a href="{{ pathjoin .ActionEndpoint "/settings/mfa/add/app" }}"> 585 <button type="button" class="btn waves-effect waves-light navbtn active"> 586 <i class="las la-undo-alt left app-btn-icon"></i> 587 <span class="app-btn-text">Try Again</span> 588 </button> 589 </a> 590 {{ end }} 591 </div> 592 </div> 593 {{ end }} 594 {{ if eq .Data.view "mfa-test-app" }} 595 <form id="mfa-test-app-form" action="{{ pathjoin .ActionEndpoint "/settings/mfa/test/app/" .Data.mfa_digits .Data.mfa_token_id }}" method="POST"> 596 <div class="row"> 597 <h1>Test MFA Authenticator Application</h1> 598 <div class="row"> 599 <div class="col s12 m12 l12"> 600 <p>Please open your MFA authenticator application to view your authentication code and verify your identity</p> 601 <div class="input-field mfa-app-auth-ctrl mfa-app-auth-form"> 602 <input class="mfa-app-auth-passcode" id="passcode" name="passcode" type="text" class="validate" pattern="[0-9]{4,8}" 603 title="Authentication code should contain 4-8 characters and consists of 0-9 characters." 604 maxlength="6" 605 autocorrect="off" autocapitalize="off" autocomplete="off" 606 placeholder="______" 607 required /> 608 </div> 609 <input id="token_id" name="token_id" type="hidden" value="{{ .Data.mfa_token_id }}" /> 610 <input id="digits" name="digits" type="hidden" value="{{ .Data.mfa_digits }}" /> 611 <div class="center-align"> 612 <button type="reset" name="reset" class="btn waves-effect waves-light navbtn active navbtn-last red lighten-1"> 613 <i class="las la-redo-alt left app-btn-icon"></i> 614 </button> 615 <button type="submit" name="submit" class="btn waves-effect waves-light navbtn active navbtn-last"> 616 <i class="las la-check-square left app-btn-icon"></i> 617 <span class="app-btn-text">Verify</span> 618 </button> 619 </div> 620 </div> 621 </div> 622 </form> 623 {{ end }} 624 {{ if eq .Data.view "mfa-test-app-status" }} 625 <div class="row"> 626 <div class="col s12"> 627 <h1>Test MFA Authenticator Application</h1> 628 <p>{{.Data.status }}: {{ .Data.status_reason }}</p> 629 {{ if eq .Data.status "SUCCESS" }} 630 <a href="{{ pathjoin .ActionEndpoint "/settings/mfa" }}"> 631 <button type="button" class="btn waves-effect waves-light navbtn active"> 632 <i class="las la-undo-alt left app-btn-icon"></i> 633 <span class="app-btn-text">Go Back</span> 634 </button> 635 </a> 636 {{ else }} 637 {{ if ne .Data.mfa_token_id "" }} 638 <a href="{{ pathjoin .ActionEndpoint "/settings/mfa/test/app/" .Data.mfa_digits .Data.mfa_token_id }}"> 639 <button type="button" class="btn waves-effect waves-light navbtn active"> 640 <i class="las la-undo-alt left app-btn-icon"></i> 641 <span class="app-btn-text">Try Again</span> 642 </button> 643 </a> 644 {{ end }} 645 {{ end }} 646 </div> 647 </div> 648 {{ end }} 649 {{ if eq .Data.view "mfa-delete-status" }} 650 <div class="row"> 651 <div class="col s12"> 652 <h1>MFA Token</h1> 653 <p>{{.Data.status }}: {{ .Data.status_reason }}</p> 654 <a href="{{ pathjoin .ActionEndpoint "/settings/mfa" }}"> 655 <button type="button" class="btn waves-effect waves-light navbtn active"> 656 <i class="las la-undo-alt left app-btn-icon"></i> 657 <span class="app-btn-text">Go Back</span> 658 </button> 659 </a> 660 </div> 661 </div> 662 {{ end }} 663 {{ if eq .Data.view "mfa-add-u2f" }} 664 <form id="mfa-add-u2f-form" action="{{ pathjoin .ActionEndpoint "/settings/mfa/add/u2f" }}" method="POST"> 665 <div class="row"> 666 <div class="col s12"> 667 <h1>Add U2F Security Key</h1> 668 <p>Please insert your U2F (USB, NFC, or Bluetooth) Security Key, e.g. Yubikey.</p> 669 <p>Then, please click "Register" button below.</p> 670 <div class="input-field"> 671 <input id="comment" name="comment" type="text" class="validate" pattern="[A-Za-z0-9 -]{4,25}" 672 title="Authentication code should contain 4-25 characters and consists of A-Z, a-z, 0-9, space, and dash characters." 673 autocorrect="off" autocapitalize="off" autocomplete="off" 674 required /> 675 <label for="comment">Comment</label> 676 </div> 677 <input class="hide" id="webauthn_register" name="webauthn_register" type="text" /> 678 <input class="hide" id="webauthn_challenge" name="webauthn_challenge" type="text" value="{{ .Data.webauthn_challenge }}" /> 679 <button id="mfa-add-u2f-button" type="button" name="action" onclick="u2f_token_register('mfa-add-u2f-form', 'mfa-add-u2f-button');" class="btn waves-effect waves-light navbtn active navbtn-last app-btn"> 680 <i class="las la-plus-circle left app-btn-icon"></i> 681 <span class="app-btn-text">Register</span> 682 </button> 683 </div> 684 </div> 685 </form> 686 {{ end }} 687 {{ if eq .Data.view "mfa-add-u2f-status" }} 688 <div class="row"> 689 <div class="col s12"> 690 <h1>U2F Security Key</h1> 691 <p>{{.Data.status }}: {{ .Data.status_reason }}</p> 692 {{ if eq .Data.status "SUCCESS" }} 693 <a href="{{ pathjoin .ActionEndpoint "/settings/mfa" }}"> 694 <button type="button" class="btn waves-effect waves-light navbtn active"> 695 <i class="las la-undo-alt left app-btn-icon"></i> 696 <span class="app-btn-text">Go Back</span> 697 </button> 698 </a> 699 {{ else }} 700 <a href="{{ pathjoin .ActionEndpoint "/settings/mfa/add/u2f" }}"> 701 <button type="button" class="btn waves-effect waves-light navbtn active"> 702 <i class="las la-undo-alt left app-btn-icon"></i> 703 <span class="app-btn-text">Try Again</span> 704 </button> 705 </a> 706 {{ end }} 707 </div> 708 </div> 709 {{ end }} 710 {{ if eq .Data.view "mfa-test-u2f" }} 711 <form id="mfa-test-u2f-form" action="{{ pathjoin .ActionEndpoint "/settings/mfa/test/u2f/generic" .Data.mfa_token_id }}" method="POST"> 712 <div class="row"> 713 <div class="col s12 m12 l12"> 714 <h1>Test Token</h1> 715 <p> 716 Insert your hardware token into a USB port. 717 Next, click "Authenticate" button below. 718 When prompted, touch, or otherwise trigger the hardware token. 719 </p> 720 <input id="webauthn_request" name="webauthn_request" type="hidden" /> 721 <a id="mfa-test-u2f-button" onclick="u2f_token_authenticate('mfa-test-u2f-form', 'mfa-test-u2f-button');" class="btn waves-effect waves-light navbtn active navbtn-last"> 722 <i class="las la-check-square left app-btn-icon"></i> 723 <span class="app-btn-text">Verify</span> 724 </a> 725 </div> 726 <input id="token_id" name="token_id" type="hidden" value="{{ .Data.mfa_token_id }}" /> 727 </div> 728 </form> 729 {{ end }} 730 {{ if eq .Data.view "mfa-test-u2f-status" }} 731 <div class="row"> 732 <div class="col s12"> 733 <h1>Test Token</h1> 734 <p>{{.Data.status }}: {{ .Data.status_reason }}</p> 735 {{ if eq .Data.status "SUCCESS" }} 736 <a href="{{ pathjoin .ActionEndpoint "/settings/mfa" }}"> 737 <button type="button" class="btn waves-effect waves-light navbtn active"> 738 <i class="las la-undo-alt left app-btn-icon"></i> 739 <span class="app-btn-text">Go Back</span> 740 </button> 741 </a> 742 {{ else }} 743 {{ if ne .Data.mfa_token_id "" }} 744 <a href="{{ pathjoin .ActionEndpoint "/settings/mfa/test/u2f/generic" .Data.mfa_token_id }}"> 745 <button type="button" class="btn waves-effect waves-light navbtn active"> 746 <i class="las la-undo-alt left app-btn-icon"></i> 747 <span class="app-btn-text">Try Again</span> 748 </button> 749 </a> 750 {{ end }} 751 {{ end }} 752 </div> 753 </div> 754 {{ end }} 755 {{ if eq .Data.view "password" }} 756 <form action="{{ pathjoin .ActionEndpoint "/settings/password/edit" }}" method="POST"> 757 <div class="row"> 758 <h1>Password Management</h1> 759 <div class="row"> 760 <div class="col s12 m6 l6"> 761 <p>If you want to change your password, please provide your current password and 762 </p> 763 <div class="input-field"> 764 <input id="secret1" name="secret1" type="password" autocorrect="off" autocapitalize="off" autocomplete="off" required /> 765 <label for="secret1">Current Password</label> 766 </div> 767 <div class="input-field"> 768 <input id="secret2" name="secret2" type="password" autocorrect="off" autocapitalize="off" autocomplete="off" required /> 769 <label for="secret2">New Password</label> 770 </div> 771 <div class="input-field"> 772 <input id="secret3" name="secret3" type="password" autocorrect="off" autocapitalize="off" autocomplete="off" required /> 773 <label for="secret3">Confirm New Password</label> 774 </div> 775 </div> 776 </div> 777 </div> 778 <div class="row right"> 779 <button type="submit" name="submit" class="btn waves-effect waves-light navbtn active navbtn-last app-btn"> 780 <i class="las la-paper-plane left app-btn-icon"></i> 781 <span class="app-btn-text">Change Password</span> 782 </button> 783 </div> 784 </form> 785 {{ end }} 786 {{ if eq .Data.view "password-edit" }} 787 <div class="row"> 788 <div class="col s12"> 789 {{ if eq .Data.status "SUCCESS" }} 790 <h1>Password Has Been Changed</h1> 791 <p>Please log out and log back in.</p> 792 {{ else }} 793 <h1>Password Change Failed</h1> 794 <p>Reason: {{ .Data.status_reason }} </p> 795 <a href="{{ pathjoin .ActionEndpoint "/settings/password" }}"> 796 <button type="button" class="btn waves-effect waves-light navbtn active"> 797 <i class="las la-undo-alt left app-btn-icon"></i> 798 <span class="app-btn-text">Try Again</span> 799 </button> 800 </a> 801 {{ end }} 802 </div> 803 </div> 804 {{ end }} 805 {{ if eq .Data.view "connected" }} 806 <div class="row"> 807 <div class="col s12"> 808 <p>No connected accounts found.</p> 809 </div> 810 </div> 811 {{ end }} 812 </div> 813 </div> 814 </div> 815 816 <!-- Optional JavaScript --> 817 <script src="{{ pathjoin .ActionEndpoint "/assets/materialize-css/js/materialize.js" }}"></script> 818 {{ if or (eq .Data.view "sshkeys-add") (eq .Data.view "gpgkeys-add") (eq .Data.view "sshkeys-view") (eq .Data.view "gpgkeys-view") }} 819 <script src="{{ pathjoin .ActionEndpoint "/assets/highlight.js/js/highlight.js" }}"></script> 820 <script src="{{ pathjoin .ActionEndpoint "/assets/highlight.js/js/languages/json.min.js" }}"></script> 821 <script src="{{ pathjoin .ActionEndpoint "/assets/highlight.js/js/languages/plaintext.min.js" }}"></script> 822 {{ end }} 823 {{ if or (eq .Data.view "apikeys-add") (eq .Data.view "apikeys-add-status") }} 824 <script src="{{ pathjoin .ActionEndpoint "/assets/highlight.js/js/highlight.js" }}"></script> 825 <script src="{{ pathjoin .ActionEndpoint "/assets/highlight.js/js/languages/json.min.js" }}"></script> 826 <script src="{{ pathjoin .ActionEndpoint "/assets/highlight.js/js/languages/plaintext.min.js" }}"></script> 827 {{ end }} 828 {{ if or (eq .Data.view "mfa-add-u2f") (eq .Data.view "mfa-test-u2f") }} 829 <script src="{{ pathjoin .ActionEndpoint "/assets/cbor/cbor.js" }}"></script> 830 {{ end }} 831 {{ if eq .Data.ui_options.custom_js_required "yes" }} 832 <script src="{{ pathjoin .ActionEndpoint "/assets/js/custom.js" }}"></script> 833 {{ end }} 834 {{ if or (eq .Data.view "mfa-add-app") (eq .Data.view "mfa-test-app") }} 835 <script src="{{ pathjoin .ActionEndpoint "/assets/js/mfa_add_app.js" }}"></script> 836 {{ end }} 837 {{ if eq .Data.view "mfa-add-u2f" }} 838 <script src="{{ pathjoin .ActionEndpoint "/assets/js/mfa_add_u2f.js" }}"></script> 839 {{ end }} 840 {{ if eq .Data.view "mfa-test-u2f" }} 841 <script src="{{ pathjoin .ActionEndpoint "/assets/js/mfa_add_u2f.js" }}"></script> 842 <script src="{{ pathjoin .ActionEndpoint "/assets/js/mfa_test_u2f.js" }}"></script> 843 {{ end }} 844 {{ if or (eq .Data.view "sshkeys-add") (eq .Data.view "gpgkeys-add") (eq .Data.view "sshkeys-view") (eq .Data.view "gpgkeys-view") }} 845 <script> 846 hljs.initHighlightingOnLoad(); 847 </script> 848 {{ end }} 849 {{ if or (eq .Data.view "apikeys-add") (eq .Data.view "apikeys-add-status") }} 850 <script> 851 hljs.initHighlightingOnLoad(); 852 </script> 853 {{ end }} 854 {{ if .Message }} 855 <script> 856 var toastHTML = '<span class="app-error-text">{{ .Message }}</span><button class="btn-flat toast-action" onclick="M.Toast.dismissAll();">Close</button>'; 857 toastElement = M.toast({ 858 html: toastHTML, 859 classes: 'toast-error' 860 }); 861 const appContainer = document.querySelector('.app-container') 862 appContainer.prepend(toastElement.el) 863 </script> 864 {{ end }} 865 {{ if eq .Data.view "mfa-add-u2f" }} 866 <script> 867 function u2f_token_register(formID, btnID) { 868 const params = { 869 challenge: "{{ .Data.webauthn_challenge }}", 870 rp_name: "{{ .Data.webauthn_rp_name }}", 871 user_id: "{{ .Data.webauthn_user_id }}", 872 user_name: "{{ .Data.webauthn_user_email }}", 873 user_display_name: "{{ .Data.webauthn_user_display_name }}", 874 user_verification: "{{ .Data.webauthn_user_verification }}", 875 attestation: "{{ .Data.webauthn_attestation }}", 876 }; 877 register_u2f_token(formID, btnID, params); 878 } 879 </script> 880 {{ end }} 881 882 {{ if eq .Data.view "mfa-test-u2f" }} 883 <script> 884 function u2f_token_authenticate(formID, btnID) { 885 const params = { 886 challenge: "{{ .Data.webauthn_challenge }}", 887 timeout: {{ .Data.webauthn_timeout }}, 888 rp_name: "{{ .Data.webauthn_rp_name }}", 889 user_verification: "{{ .Data.webauthn_user_verification }}", 890 {{ if .Data.webauthn_credentials }} 891 allowed_credentials: [ 892 {{ range .Data.webauthn_credentials }} 893 { 894 id: "{{ .id }}", 895 type: "{{ .type }}", 896 transports: [{{ .transports }}], 897 }, 898 {{ end }} 899 ], 900 {{ else }} 901 allowed_credentials: [], 902 {{ end }} 903 ext_uvm: {{ .Data.webauthn_ext_uvm }}, 904 ext_loc: {{ .Data.webauthn_ext_loc }}, 905 ext_tx_auth_simple: "{{ .Data.webauthn_tx_auth_simple }}", 906 }; 907 authenticate_u2f_token(formID, btnID, params); 908 } 909 </script> 910 {{ end }} 911 </body> 912 </html>