mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-05-06 10:20:43 +00:00
Tests:
- Setup: add domain name mystable.example. Add an entry in /etc/hosts on the
test machine. In Firefox, in about:config, set
'security.webauthn.allow_with_certificate_override' to 'true'.
- Registration
- Passkey successful registration:
- After passkey registration, created time is time at which key is created.
- After passkey registration, domain is the domain with which the interface
is accessed at the time of addition of passkey.
- After passkey registration, Added and Last Used columns show the current
time in UTC. Signature counter and extensions and aaguid values in the DB
are as expected.
- First key's name is 'Key 1'. After that it is 'Key 2' and so on. If a key
is renamed as 'Key 4', then next key will be named 'Key 5'.
- Registering passkeys using testing container stable container works.
- Links:
- 'Manage passkeys' link is show in the user menu in navbar in both desktop
mode and mobile mode. Clicking on it redirects the browser to current
user's passkey management page.
- User's edit page shows 'Use passkeys for better security'. Clicking on the
link redirects the browser to passkey management page for the user who's
account is being edited.
- Listing:
- All passkeys are show properly. Name, domain, added, last used, and
operations show correctly.
- When using a browser without Javascript script shows an error alert.
- If not passkeys are present "No passkeys added to user account." message
is shown.
- Editing the passkey shows correct page. Title, heading, form labels, form
value, and buttons are as expected. After editing, passkey is updated
properly.
- Deleting the passkey shows a model dialog with correct details. After
confirmation, passkey is removed and page is refreshed.
- Error handling:
- On GNOME's Web, clicking the 'Add Passkey' shows the error 'Browser does
not support passkeys'.
- On Chromium, clicking the 'Add passkey' shows the error 'NotAllowedError:
WebAuthn is not supported on sites with TLS certificate errors.'
- Raising an error in passkey_add_begin() results in correct error message
shown with 'Add passkey' button is clicked. Status code is 500.
- Raising an error in passkey_add_complete() results in correct error
message shown after unlocking the hardware token. Status code is 500.
- Canceling the PIN dialog results in '...user denied permission' error
alert.
- Canceling the touch dialog results in '...user denied permission' error
alert.
- Multiple failed attempts result in multiple alerts being shown at the same
time.
- Editing another user's passkeys:
- Listing passkeys show correct list of passkeys for the user account being
managed.
- Adding passkeys adds correctly to the user account being managed.
- Editing passkey correctly edits passkey of the user account being managed.
Redirect happens to the correct page after.
- Deleting passkey correctly edits passkey of the user account being
managed. Redirect happens to the correct page after.
- If a non-admin user tries to access passkeys list/edit/delete URL of
another user, 403 Forbidden error is raised
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
296 lines
12 KiB
HTML
296 lines
12 KiB
HTML
{% load i18n %}
|
|
{% load static %}
|
|
{% load extras %}
|
|
|
|
{% comment %}
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
{% endcomment %}
|
|
<!doctype html>
|
|
<html class="no-js" lang="en">
|
|
<!-- the "no-js" class will be removed if Javascript is turned on -->
|
|
<head>
|
|
<meta charset="utf-8">
|
|
|
|
<!-- Always force latest IE rendering engine and Chrome Frame -->
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
|
|
<!-- Mobile Viewport Fix http://j.mp/mobileviewport & http://davidbcalhoun.com/2010/viewport-metatag
|
|
device-width : Occupy full width of the screen in its current orientation
|
|
initial-scale = 1.0 retains dimensions instead of zooming out if page height > device height
|
|
maximum-scale = 1.0 retains dimensions instead of zooming in if page width < device width
|
|
-->
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
<!-- R2D2, you know better than to trust a strange computer! -->
|
|
<meta name="robots" content="noindex, nofollow, noarchive">
|
|
<meta name="googlebot" content="noindex, nofollow, noarchive, nosnippet, noodp, noimageindex, notranslate">
|
|
<meta name="msnbot" content="noindex, nofollow, noarchive, noodp">
|
|
<meta name="slurp" content="noindex, nofollow, noarchive, noodp, noydir">
|
|
<meta name="application-name" content="{{ box_name }}">
|
|
<meta name="description"
|
|
content="{% blocktrans trimmed %}
|
|
FreedomBox is a personal server designed for privacy and
|
|
data ownership. It is free software that lets you install
|
|
and manage server apps with ease.
|
|
{% endblocktrans %}">
|
|
{% block title %}
|
|
<title>
|
|
{% if title %} {{ title }} {% else %} {{ box_name }} {% endif %}
|
|
</title>
|
|
{% endblock %}
|
|
|
|
<!-- Favicon. Works with IE >= 11 and other GUI browsers -->
|
|
<link rel="icon" type="image/png"
|
|
href="{% static 'theme/img/freedombox-logo-32px.png' %}">
|
|
|
|
<!-- The is the icon for iOS's Web Clip. Size: 57x57 for older iPhones, 72x72 for iPads, 114x114 for iPhone4
|
|
- To prevent iOS from applying its styles to the icon name it thusly: apple-touch-icon-precomposed.png
|
|
- Transparency is not recommended (iOS will put a black BG behind the icon) -->
|
|
<link rel="apple-touch-icon" sizes="57x57" href="{% static 'theme/img/apple-touch-icon-57px-precomposed.png' %}">
|
|
<link rel="apple-touch-icon" sizes="72x72" href="{% static 'theme/img/apple-touch-icon-72px-precomposed.png' %}">
|
|
<link rel="apple-touch-icon" sizes="114x114" href="{% static 'theme/img/apple-touch-icon-114px-precomposed.png' %}">
|
|
|
|
<!-- Stylesheets -->
|
|
<link rel="stylesheet" href="{% static '/javascript/bootstrap5/css/bootstrap.min.css' %}">
|
|
<link rel="stylesheet" href="{% static 'theme/css/main.css' %}">
|
|
{% if user_css %}
|
|
<link rel="stylesheet" href="{% static user_css %}">
|
|
{% endif %}
|
|
|
|
<!-- This script is not loaded in defer mode because it needs to run before
|
|
page is rendered -->
|
|
<script src="{% static 'theme/js/color-modes.js' %}"></script>
|
|
<!-- Local link to system Bootstrap JS -->
|
|
<script src="{% static '/javascript/popperjs2/popper.min.js' %}" defer></script>
|
|
<script src="{% static '/javascript/bootstrap5/js/bootstrap.bundle.min.js' %}" defer></script>
|
|
<script src="{% static '/javascript/htmx/htmx.min.js' %}" defer></script>
|
|
|
|
<script src="{% static 'theme/js/main.js' %}" defer></script>
|
|
{% block app_js %}<!-- placeholder for app-specific js files -->{% endblock %}
|
|
{% block page_js %}<!-- placeholder for page-specific js files -->{% endblock %}
|
|
|
|
{% if refresh_page_sec is not None %}
|
|
<noscript>
|
|
<meta http-equiv="refresh" content="{{ refresh_page_sec }}" />
|
|
</noscript>
|
|
{% endif %}
|
|
|
|
{% block app_head %}<!-- placeholder for app/module-specific head files -->{% endblock %}
|
|
{% block page_head %}<!-- placeholder for page-specific head files -->{% endblock %}
|
|
</head>
|
|
|
|
<body class="{%block body_class %}{%endblock%}"
|
|
{% if refresh_page_sec is not None %}
|
|
data-refresh-page-sec="{{ refresh_page_sec }}"
|
|
{% endif %}>
|
|
{% block wrapper %}
|
|
<div id="wrapper">
|
|
<div class="main-header fixed-top">
|
|
<div class="container">
|
|
<nav class="navbar navbar-expand-md">
|
|
|
|
{% block mainmenu_left %}
|
|
{% url 'index' as index_url %}
|
|
<a href="{{ index_url }}" class="navbar-brand
|
|
{% if index_url == active_section_url %}active{% endif %}"
|
|
title="{{ box_name }}">
|
|
{% icon 'freedombox' %}
|
|
</a>
|
|
{% endblock %}
|
|
|
|
{% block notifications_dropdown %}
|
|
<ul class="navbar-nav">
|
|
{% include "notifications-dropdown.html" %}
|
|
</ul>
|
|
{% endblock %}
|
|
|
|
{% block mainmenu_toggler %}
|
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
|
|
data-bs-target="#navbar-collapse" aria-controls="navbar-collapse"
|
|
aria-expanded="false" aria-label="Toggle navigation">
|
|
{% icon 'bars' %}
|
|
</button>
|
|
{% endblock %}
|
|
|
|
<div class="collapse navbar-collapse" id="navbar-collapse">
|
|
<ul class="navbar-nav flex-grow-1">
|
|
{% block mainmenu_left_collapse %}
|
|
{% if user.is_authenticated and user_is_admin %}
|
|
<li class="nav-item">
|
|
{% url 'index' as index_url %}
|
|
<a href="{{ index_url }}" title='{% trans " Home" %}'
|
|
class="nav-link {% if index_url == active_section_url %}
|
|
active{% endif %}">
|
|
{% trans "Home" %}
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
{% url 'apps' as apps_url %}
|
|
<a href="{{ apps_url }}" title='{% trans " Apps" %}'
|
|
class="nav-link {% if apps_url == active_section_url %}
|
|
active{% endif %}">
|
|
{% icon 'th' %}
|
|
{% trans "Apps" %}
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
{% url 'system' as system_url %}
|
|
<a href="{{ system_url }}" title='{% trans " System" %}'
|
|
class="nav-link {% if system_url == active_section_url %}
|
|
active{% endif %}">
|
|
{% icon 'cog' %}
|
|
{% trans "System" %}
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
{% endblock %}
|
|
</ul>
|
|
<ul class="navbar-nav">
|
|
{% block mainmenu_right %}
|
|
|
|
{% if user.is_authenticated %}
|
|
|
|
{% include "notifications-dropdown.html" %}
|
|
|
|
{% include "theme-menu.html" %}
|
|
|
|
{% include "help-menu.html" %}
|
|
|
|
<li id="id_user_menu" class="nav-item dropdown">
|
|
<a href="{% url 'users:edit' request.user.username %}"
|
|
class="nav-link dropdown-toggle" data-bs-toggle="dropdown"
|
|
role="button" aria-expanded="false" aria-haspopup="true"
|
|
id="id_user_menu_link">
|
|
{% icon 'user' %}
|
|
{{ request.user.username }}
|
|
</a>
|
|
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-xxl-start"
|
|
role="menu" aria-labelledby="id_user_menu_link">
|
|
<li>
|
|
<a id="id_user_edit_menu" class="dropdown-item"
|
|
href="{% url 'users:edit' request.user.username %}"
|
|
title="{% trans "Edit"%}">
|
|
{% trans "Edit" %}
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a id="id_manage_passkeys_menu" class="dropdown-item"
|
|
href="{% url 'users:passkeys' request.user.username %}"
|
|
title="{% trans "Manage passkeys" %}">
|
|
{% trans "Manage passkeys" %}
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a id="id_change_password_menu" class="dropdown-item"
|
|
href="{% url 'users:change_password' request.user.username %}"
|
|
title="{% trans "Change password" %}">
|
|
{% trans "Change password" %}
|
|
</a>
|
|
</li>
|
|
<li class="dropdown-divider d-none d-md-block"></li>
|
|
{% if user_is_admin %}
|
|
<li>
|
|
<a class="dropdown-item" href="{% url 'power:restart' %}"
|
|
title="{% trans "Restart"%}">
|
|
{% trans "Restart" %}
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a class="dropdown-item" href="{% url 'power:shutdown' %}"
|
|
title="{% trans "Shut down" %}">
|
|
{% trans "Shut down" %}
|
|
</a>
|
|
</li>
|
|
<li class="dropdown-divider d-none d-md-block"></li>
|
|
{% endif %}
|
|
<li>
|
|
<form class="form form-logout" method="post"
|
|
action="{% url 'users:logout' %}">
|
|
{% csrf_token %}
|
|
<input type="submit" class="dropdown-item no-running-status"
|
|
value="{% trans "Log out" %}">
|
|
</form>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
{% else %}
|
|
<li class="nav-item">
|
|
<a class="nav-link"
|
|
href="{% url 'language-selection' %}?next={{ request.path|iriencode }}"
|
|
title="{% trans "Select language" %}">
|
|
{% icon 'globe-w' %}
|
|
<span class="nav-text d-inline-block d-md-none">
|
|
{% trans "Select language" %}
|
|
</span>
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{% url 'help:about' %}"
|
|
title="{% trans "About" %}">
|
|
{% icon 'question-circle' %}
|
|
<span class="nav-text d-inline-block d-md-none">
|
|
{% trans "About" %}
|
|
</span>
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="{% url 'users:login' %}"
|
|
title="{% trans "Log in" %}">
|
|
{% icon 'user' %}
|
|
{% trans "Log in" %}</a>
|
|
</li>
|
|
{% endif %}
|
|
|
|
{% if user.is_authenticated %}
|
|
<form id="logout-nojs" class="form form-inline form-logout nav-item"
|
|
method="post" action="{% url 'users:logout' %}">
|
|
{% csrf_token %}
|
|
<input type="submit" class="nav-link no-running-status btn btn-link"
|
|
value="{% trans "Log out" %}">
|
|
</form>
|
|
{% endif %}
|
|
{% endblock %}
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
{% include "notifications.html" %}
|
|
</div>
|
|
</div>
|
|
|
|
{% block container %}
|
|
<div id="content-block" class="container content-container"
|
|
{% if refresh_page_sec %}
|
|
hx-get="." hx-trigger="load delay:{{ refresh_page_sec }}s"
|
|
hx-select="#content-block" hx-target="#content-block" hx-swap="outerHTML"
|
|
{% endif %}>
|
|
{% block content_row %}
|
|
{% include 'messages.html' %}
|
|
|
|
{% block breadcrumbs %}
|
|
{% include 'breadcrumbs.html' %}
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
{# main content goes here #}
|
|
{% endblock %}
|
|
{% endblock %}
|
|
</div>
|
|
{% endblock %}
|
|
|
|
<footer>
|
|
<div class="container">
|
|
{% block footer_block %}
|
|
{% endblock %}
|
|
</div>
|
|
|
|
<div class="d-none">
|
|
<a href="{% static 'jslicense.html' %}" data-jslicense="1">
|
|
{% trans "JavaScript license information" %}</a>
|
|
</div>
|
|
</footer><!--/.footer-->
|
|
</div><!--/#container-->
|
|
{% endblock %}
|
|
</body>
|
|
</html>
|