botbook/node_modules/@azure/static-web-apps-cli/dist/public/auth.html
Rodrigo Rodriguez 6ae15fe3e5 Updated.
2024-09-04 13:13:15 -03:00

374 lines
15 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Azure Static Web Apps Emulator - Authentication Portal</title>
<link rel="shortcut icon" href="https://appservice.azureedge.net/images/static-apps/v3/favicon.svg" type="image/x-icon" />
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/4.1.1/css/bootstrap.min.css" crossorigin="anonymous" />
<style>
html,
body {
height: 100%;
}
body {
display: flex;
flex-direction: column;
}
.container-height {
flex: 1 0 auto;
}
footer {
flex-shrink: 0;
width: 100%;
background-color: #f5f5f5;
left: -1px;
padding: 10px;
display: flex;
font-size: 0.8em;
justify-content: space-between;
}
footer nav {
display: flex;
}
footer ul {
list-style: none;
display: flex;
}
footer li {
margin: 0 10px;
}
</style>
</head>
<body>
<nav class="navbar navbar-light">
<div class="navbar-brand">
<div class="container pl-4 ml-5">
<img src=https://appservice.azureedge.net/images/static-apps/v3/microsoft_azure_logo.svg width="270" height="108" alt />
</div>
</div>
</nav>
<div class="container-fluid container-height mr-1">
<div class="row">
<div class="row col-xs-12 col-sm-12 d-block d-lg-none d-xl-none d-md-block d-sm-block d-xs-block">
<div class="text-center"><img src=https://appservice.azureedge.net/images/static-apps/v3/staticapps.svg /></div>
</div>
<div
class="
extra-pl-small-scr
offset-xl-1 offset-lg-1 offset-md-2 offset-sm-2 offset-xs-4
col-xl-5 col-lg-5 col-md-10 col-sm-11 col-xs-11
div-vertical-center
"
>
<div class="container-fluid">
<h1 class="pb-4">Azure Static Web Apps Auth</h1>
<form action="" name="auth">
<div class="form-group row">
<label for="identityProvider" class="col-4 col-form-label">Provider</label>
<div class="col-8">
<input
disabled
id="identityProvider"
name="identityProvider"
list="providers-list"
placeholder="Choose an auth provider"
type="text"
required="required"
class="form-control"
/>
<small id="identityProviderHelpBlock" class="form-text text-muted">Name of the identity provider</small>
</div>
<datalist id="providers-list">
<option value="aad"></option>
<option value="google"></option>
<option value="github"></option>
<option value="twitter"></option>
<option value="facebook"></option>
<option value="openid"></option>
</datalist>
</div>
<div class="form-group row">
<label for="userId" class="col-4 col-form-label">User ID</label>
<div class="col-8">
<input
id="userId"
name="userId"
autocomplete="off"
placeholder="Choose a user ID"
type="text"
aria-describedby="userIdHelpBlock"
required="required"
class="form-control"
/>
<small id="userIdHelpBlock" class="form-text text-muted">An Azure Static Web Apps-specific unique ID for the user</small>
</div>
</div>
<div class="form-group row">
<label for="userDetails" class="col-4 col-form-label">Username</label>
<div class="col-8">
<input
id="userDetails"
name="userDetails"
autocomplete="off"
placeholder="Choose a username"
type="text"
aria-describedby="userDetailsHelpBlock"
required="required"
class="form-control"
/>
<small id="userDetailsHelpBlock" class="form-text text-muted">Username or email address of the user</small>
</div>
</div>
<div class="form-group row">
<label for="userRoles" class="col-4 col-form-label">User's roles</label>
<div class="col-8">
<textarea id="userRoles" name="userRoles" cols="40" rows="3" class="form-control" aria-describedby="userRolesHelpBlock"></textarea>
<small id="userRolesHelpBlock" class="form-text text-muted">Roles used during authorization. One role per line.</small>
<small id="userRolesHelpBlock" class="form-text text-muted"
>Note: roles "authenticated" and "anonymous" will be added automatically if not provided.</small
>
</div>
</div>
<div class="form-group row">
<label for="claims" class="col-4 col-form-label">User's claims</label>
<div class="col-8">
<textarea
id="claims"
name="claims"
cols="40"
rows="3"
class="form-control"
aria-describedby="userClaimsHelpBlock"
placeholder="[{'typ': 'name','val': 'Azure Static Web Apps'}]"
></textarea>
<small id="userClaimsHelpBlockError" class="d-none form-text text-muted alert alert-danger">Invalid JSON value!</small>
<small id="userClaimsHelpBlock" class="form-text text-muted"
>Claims from the identity provider. JSON array of claims. See
<a href="https://docs.microsoft.com/azure/static-web-apps/user-information">documentation</a> for example claims.</small
>
</div>
</div>
<div class="form-group row">
<div class="col-4"></div>
<div class="col-8 text-right">
<button name="submit" id="submit" type="submit" class="btn btn-primary">Login</button>
<button name="clear" id="clear" type="button" class="btn btn-outline-danger">Clear</button>
</div>
</div>
</form>
</div>
</div>
<div class="col-xl-5 col-lg-5 col-md-12 d-none d-lg-block">
<div class="text-center">
<img src="https://appservice.azureedge.net/images/static-apps/v3/staticapps.svg" />
</div>
</div>
</div>
</div>
<footer>
<div>Azure Static Web Apps emulator (<a rel="noopener noreferrer" target="_blank" href="https://github.com/Azure/static-web-apps-cli/commit/8d0b7aa">main+sha.8d0b7aa</a>)</div>
<nav>
<ul>
<li><a href="https://github.com/azure/static-web-apps-cli/blob/master/CONTRIBUTING.md">Contribute</a></li>
<li><a href="https://docs.microsoft.com/azure/static-web-apps/">Documentation</a></li>
<li><a href="https://privacy.microsoft.com/privacystatement">Privacy & Cookies</a></li>
<li><a href="https://www.microsoft.com/legal/intellectualproperty/copyright">Terms of Use</a></li>
</ul>
</nav>
<div class="copyright">© Microsoft 2023</div>
</footer>
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.2.1.min.js" crossorigin="anonymous"></script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/4.1.1/bootstrap.min.js" crossorigin="anonymous"></script>
<script>
const defaultRoles = ["anonymous", "authenticated"];
const defaultClaims = "[]"; // this should be a valid JSON string
function saveCookie(formElement) {
const data = localStorage[hashStorageKey(formElement)];
document.cookie = `StaticWebAppsAuthCookie=${btoa(data)}; path=/`;
}
function redirectToApp() {
const defaultRedirectPath = "/";
try {
const metaSearch = document.querySelector(`meta[name="swa:originalSearch"]`)?.content || "";
const redirectPath = metaSearch || window.location.search || defaultRedirectPath;
const urlSearch = (metaSearch || location.search).replace("?", "");
const urlQuery = urlSearch && Object.fromEntries(new Map(urlSearch.split("&").map((query) => query.split("="))));
const postLoginRedirectUri = urlQuery ? urlQuery["post_login_redirect_uri"] : redirectPath;
window.location.href = decodeURIComponent(postLoginRedirectUri) || defaultRedirectPath;
} catch (error) {
console.warn(error);
window.location.href = defaultRedirectPath;
}
}
function parseIdentityProviderFromUrl() {
const pathname = document.querySelector(`meta[name="swa:originalPath"]`)?.content || window.location.pathname;
if (pathname.includes("/.auth/login")) {
return pathname.split("/").pop();
} else {
return null;
}
}
function syncIdentityProviderFromUrl(formElement) {
// @TODO handle unknown providers
const identityProviderName = parseIdentityProviderFromUrl();
const providerElement = $("#identityProvider");
if (providerElement.val() === "") {
providerElement.val(identityProviderName);
providerElement.saveToLocalStorage();
} else {
// custom routes: let the user enter their provider
providerElement.removeAttr("disabled");
}
}
function hashStorageKey(element) {
const formElement = element.closest("form");
const providerName = parseIdentityProviderFromUrl();
const formName = formElement.attr("name");
return `${formName}@${providerName}`;
}
function generateUserId() {
return [...Array(32)].map(() => Math.floor(Math.random() * 16).toString(16)).join("");
}
$.fn.saveToLocalStorage = function saveToLocalStorage(options) {
const settings = $.extend({}, options);
if (typeof Storage == "undefined") {
console.warn("localStorage is not available. Auth data will not be cached!");
return false;
}
return this.each(function () {
const element = $(this);
const storageKey = hashStorageKey(element);
if (!localStorage[storageKey]) {
localStorage[storageKey] = "{}";
}
const inputName = element.attr("name");
const inputValue = element.val();
let data = JSON.parse(localStorage[storageKey]);
if (inputName === "userRoles") {
// ensure default roles are included
data[inputName] = [...new Set([...inputValue.trim().split("\n"), ...defaultRoles])];
} else if (inputName === "claims") {
const claimsErrorBlock = $("#userClaimsHelpBlockError");
const formSubmitBtn = $("#submit");
try {
claimsErrorBlock.addClass("d-none");
formSubmitBtn.prop("disabled", false);
data[inputName] = JSON.parse(inputValue);
} catch (error) {
claimsErrorBlock.removeClass("d-none");
formSubmitBtn.prop("disabled", true);
data[inputName] = JSON.parse(defaultClaims);
}
} else {
data[inputName] = inputValue;
}
localStorage[storageKey] = JSON.stringify(data);
});
};
$.fn.syncFromLocalStorage = function syncFromLocalStorage(options) {
const settings = $.extend({}, options);
return this.each(function () {
const element = $(this);
const storageKey = hashStorageKey(element);
let data = {};
if (typeof Storage == "undefined") {
console.warn("localStorage is not available. Auth data will not be cached!");
return false;
}
if (localStorage[storageKey]) {
data = JSON.parse(localStorage[storageKey]);
if (!data) {
// initialize localStorage to empty object
localStorage[storageKey] = JSON.stringify({});
data = JSON.parse(localStorage[storageKey]);
}
}
element.find("input, textarea").each(function () {
const input = $(this);
const inputName = input.attr("name");
if (inputName === "userRoles") {
const userRoles = data[inputName];
if (Array.isArray(userRoles)) {
input.val(userRoles.join("\n"));
} else if (input.val() === "") {
// set default values and cache entry
input.val(settings.defaultRoles.join("\n"));
input.saveToLocalStorage();
}
} else if (inputName === "identityProvider") {
// don't restore provider name from storage.
// this value will be taken from the URL
} else if (inputName === "userId") {
const userId = data[inputName] || generateUserId();
input.val(userId);
input.saveToLocalStorage();
} else if (inputName === "claims") {
const userClaims = data[inputName];
if (Array.isArray(userClaims)) {
input.val(JSON.stringify(userClaims, null, 2));
} else if (!userClaims || input.val() === "") {
// set default values and cache entry
input.val(settings.defaultClaims);
input.saveToLocalStorage();
}
} else if (input.attr("type") !== "submit") {
const value = data[inputName];
input.val(value);
}
});
});
};
</script>
<script>
$(function () {
// setup default values
const form = $("form[name='auth']");
// trigger on first call
form.syncFromLocalStorage({
defaultRoles,
defaultClaims,
});
// get default provider name from URL
syncIdentityProviderFromUrl(form);
// delegate storing auth info to each input
form.on("keyup", "input, textarea", (event) => $(event.currentTarget).saveToLocalStorage());
// clear form
$("#clear").click(() => {
form.find("input[type=text]:not(#identityProvider)").val("");
form.find("textarea#userRoles").val(defaultRoles.join("\n"));
form.find("textarea#claims").val(defaultClaims);
form.find("#userId").val(generateUserId());
form.find("input, textarea").each((idx, element) => $(element).saveToLocalStorage());
});
// store cookie info as base64
form.submit(() => {
event.preventDefault();
saveCookie(form);
redirectToApp();
});
});
</script>
</body>
</html>