Skip to content

Commit 61bd6d5

Browse files
committed
Merge branch 'master' of https://github.com/w3c/webappsec
2 parents 7371c20 + cad467c commit 61bd6d5

File tree

16 files changed

+4670
-737
lines changed

16 files changed

+4670
-737
lines changed

demos/credential-management/favicon.ico

Whitespace-only changes.
Lines changed: 43 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,44 @@
1-
<style>
2-
button {
3-
display: block;
4-
}
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Credential Management API Demo</title>
5+
<link href="style.css" rel="stylesheet"></link>
6+
<script defer src="script.js"></script>
7+
<meta charset="UTF-8">
8+
</head>
9+
<body class="signedout">
10+
<header>
11+
<h1>Exciting Website</h1>
12+
<button id="signin">Sign In</button>
13+
</header>
14+
<section class="signedout">
15+
Signed out.
16+
</section>
17+
<section class="signedin">
18+
<p>Welcome, <var id="displayed-username">name</var>!</p>
19+
<button id="signout">Sign Out</button>
20+
</section>
21+
<section>
22+
<p>
23+
This is where this websites' content would go if it was a real website.
24+
Until then, lorem ipsum!
25+
</p>
26+
<p>Lorem ipsum dolor sït amet, sed éu dicit qûodsï sénserit. Id possïm çaûsaê meî, alîquip pérsècutï instructiœr te ëam, éx mél aliqùam çonsëtetur vituperatorîbùs. Cu his ullùm vïvendo dîsputâtioni, moderàtius scrîptorèm no dùo, eî quî diçô nobîs adolésçens! Ex sît ïllud delïcata, nœ ërrèm reprèhéndunt his.</p>
27+
<p>Usu in soleat luptàtûm àdversarîum. Animal întellégat éx mël, ad quo consul habèmus quaéstîo. Té nèc illum iudicàbît. Dêcorè ménandri për èî. In pro quas hàbémùs quaêrendûm.</p>
28+
<p>Sêd ne porrœ vivendùm sadïpscing, accumsan mênandri accusàmûs ïn meî, nàtum îracundïà àt ëàm. Vivëndûm elêïfênd cum ei, in aeque legimûs plaçerat mêî? Mêà ex tâtîœn exercî vôluptûà, libêr laudem vèrïtus vèl in. Eu âlïqùip èlàborarét quo, mèa no pèrsius urbanitâs sïgniferumqûè? Pri te solûta pôsîdonïum, zril apeïrian voluptatùm îd îus, ëà vim caûsâê deleniti dêlëctûs?</p>
29+
<p>Te vix odiô summo contêntiœnès! Né modo ïntéllegebàt éam. Agàm quas êum èû! Cû qùî affert patrioque. Pri an ïdqûè mëlîus, sèa êi illud vîtaë.</p>
30+
</section>
31+
<dialog>
32+
<form>
33+
<!-- UGLY HACK: working around https://crbug.com/529272
34+
<label for="username">Username:</label>
35+
<input id="username" type="text" name="username" autocomplete="username"></input>
36+
<label for="password">Password:</label>
37+
<input id="password" type="password" name="password" autocomplete="new-password"></input>
38+
<input type="submit">
39+
-->
40+
</form>
41+
</dialog>
42+
</body>
43+
</html>
544

6-
div {
7-
display: none;
8-
}
9-
</style>
10-
<button id="signin-button">Sign In</button>
11-
<button id="signout-button">Sign Out</button>
12-
<div>
13-
<form id="signin">
14-
<h2>Sign In!</h2>
15-
<label for="username">Username:</label>
16-
<input id="username" name="username" autocomplete="username"></input>
17-
<label for="password">Password:</label>
18-
<input id="password" name="password" autocomplete="current-password"></input>
19-
<input type="submit">
20-
</form>
21-
<form id="signup">
22-
<h2>Sign Up!</h2>
23-
<label for="username-signup">Username:</label>
24-
<input id="username-signup" name="username" autocomplete="username"></input>
25-
<label for="password-signup">Password:</label>
26-
<input id="password-signup" name="password" autocomplete="new-password"></input>
27-
<input type="submit">
28-
</form>
29-
</div>
30-
<script>
31-
// Attempt to automatically sign a user in.
32-
if (navigator.credentials) {
33-
console.log("Automagical sign in?");
34-
navigator.credentials.get({
35-
'password': true,
36-
'suppressUI': true
37-
}).then(function (credential) {
38-
if (credential) {
39-
console.log("Got credentials! Signing in!");
40-
document.querySelector('button').innerText = "Signed in!";
41-
return;
42-
}
43-
44-
console.log("No credentials. Sadness abounds.");
45-
});
46-
}
47-
48-
// When a user clicks on the sign in button, grab a credential, or render a sign in form.
49-
document.querySelector('button').addEventListener('click', function () {
50-
if (navigator.credentials) {
51-
console.log("Manually-toggled credentials.get!");
52-
navigator.credentials.get({ 'password': true }).then(function (credential) {
53-
if (!credential) {
54-
console.log("Still no credentials. Moar sadness.");
55-
toggleSignInForm();
56-
return;
57-
}
58-
59-
console.log("Got credentials! Signing in!");
60-
document.querySelector('button').innerText = "Signing in!";
61-
});
62-
} else {
63-
toggleSignInForm();
64-
}
65-
});
66-
67-
function toggleSignInForm() {
68-
document.querySelector('button').style.display = 'none';
69-
document.querySelector('div').style.display = 'block';
70-
}
71-
72-
// Capture "Sign Up" calls, store credentials.
73-
document.querySelector('#signup').addEventListener('submit', function (e) {
74-
if (navigator.credentials) {
75-
console.log("Creating credentials!");
76-
var c;
77-
try {
78-
c = new PasswordCredential({
79-
id: document.querySelector('#username-signup').value,
80-
password: document.querySelector('#password-signup').value
81-
});
82-
} catch (e) {
83-
c = new PasswordCredential(
84-
document.querySelector('#username-signup').value,
85-
document.querySelector('#password-signup').value
86-
);
87-
}
88-
navigator.credentials.store(c).then(function () {
89-
console.log("Stored credential!");
90-
});
91-
e.preventDefault();
92-
return false;
93-
}
94-
});
95-
96-
// Capture "sign out" calls.
97-
document.querySelector('#signout-button').addEventListener('click', function () {
98-
navigator.credentials.requireUserMediation();
99-
});
100-
101-
[].forEach.call(document.querySelectorAll('input[type=submit]'), function(el) {
102-
});
103-
</script>

demos/credential-management/script.js

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* First, try to log the user in automatically by calling `get()`, and passing
3+
* in the `suppressUI` option. If the user can be unambigiously signed in (e.g.
4+
* there is one and only one valid credential for the origin, and the user has
5+
* the auto-sign-in option set), then credentials will be provided.
6+
*/
7+
if (navigator.credentials) {
8+
console.log("Trying automatic sign-in.");
9+
navigator.credentials.get({
10+
password: true,
11+
suppressUI: true
12+
}).then(processResponse);
13+
}
14+
15+
function toggleState() {
16+
console.log("Toggling UI state.");
17+
document.body.classList.toggle('signedin');
18+
document.body.classList.toggle('signedout');
19+
}
20+
21+
function processResponse(c) {
22+
if (c) {
23+
console.log("Got credentials for %s!", c.id);
24+
25+
// In a real site, we'd do something like the following to asynchronously
26+
// sign the user in:
27+
//
28+
// var fd = c.toFormData();
29+
// fetch("https://example.com/signinEndpoint/", { body: fd, method: "POST" })
30+
// .then(function (response) {
31+
// if ([check that the response is a valid signin event])
32+
// updateUI();
33+
// });
34+
//
35+
// Here, we'll just update the UI:
36+
toggleState();
37+
document.querySelector('var').textContent = c.id;
38+
}
39+
}
40+
41+
/*
42+
* Next, wire up the "Sign In" button to call `get()` without the `suppressUI`
43+
* option, and to fall back to a sign in form if the API is not available (or
44+
* if no credential is provided).
45+
*/
46+
document.querySelector('#signin').addEventListener('click', function () {
47+
console.log("Clicked 'sign in!'");
48+
if (navigator.credentials) {
49+
navigator.credentials.get({
50+
password: true
51+
}).then(function (c) {
52+
processResponse(c);
53+
if (!c) {
54+
document.querySelector('form').innerHTML = '<label for="username">Username:</label><input id="username" type="text" name="username" autocomplete="username"></input><label for="password">Password:</label><input id="password" type="password" name="password" autocomplete="new-password"></input><input type="submit">';
55+
document.querySelector('dialog').showModal();
56+
}
57+
});
58+
} else {
59+
document.querySelector('form').innerHTML = '<label for="username">Username:</label><input id="username" type="text" name="username" autocomplete="username"></input><label for="password">Password:</label><input id="password" type="password" name="password" autocomplete="new-password"></input><input type="submit">';
60+
document.querySelector('dialog').showModal();
61+
}
62+
});
63+
64+
/*
65+
* Wire up the 'Sign Out' link to call `requireUserMediation()`
66+
*/
67+
document.querySelector('#signout').addEventListener('click', function () {
68+
console.log("Clicked 'sign out!'");
69+
if (navigator.credentials)
70+
navigator.credentials.requireUserMediation();
71+
document.body.classList.toggle('signedin');
72+
document.body.classList.toggle('signedout');
73+
});
74+
75+
/*
76+
* Finally, we'll wire up the submit button on the form to call `store()` upon
77+
* submission if the API is available.
78+
*/
79+
document.querySelector('form').addEventListener('submit', function (e) {
80+
console.log("Submitted a sign-in form.");
81+
e.preventDefault();
82+
83+
if (navigator.credentials) {
84+
var c = new PasswordCredential({
85+
id: document.querySelector('#username').value,
86+
password: document.querySelector('#password').value,
87+
iconURL: getFace(document.querySelector('#username').value)
88+
});
89+
90+
navigator.credentials.store(c).then(function (a) { console.log(a); }).catch(function (e) { console.log(e); });
91+
}
92+
93+
// Sign the user in asynchronously using the data in the form. This will either look like
94+
// the code in `processResponse()` above (if the credentials API is available), or
95+
// something like the following if it's not:
96+
//
97+
// fetch("https://example.com/signinEndpoint/",
98+
// { body: new FormData(document.querySelector('form')), method: "POST" });
99+
//
100+
// Note that we call `e.preventDefault()` at the top of this event handler to prevent
101+
// the actual form submission while we do the asynchronous request.
102+
103+
toggleState();
104+
document.querySelector('var').textContent = document.querySelector('#username').value;
105+
document.querySelector('dialog').close();
106+
107+
// Clear out the form's value, because we're not actually navigating... fake it.
108+
document.querySelector('#username').value = "";
109+
document.querySelector('#password').value = "";
110+
111+
return false;
112+
});
113+
114+
function getFace(string) {
115+
var hashString = function() {
116+
var hash = 0, i, chr, len;
117+
if (string.length == 0) return hash;
118+
for (i = 0, len = string.length; i < len; i++) {
119+
chr = string.charCodeAt(i);
120+
hash = ((hash << 5) - hash) + chr;
121+
hash |= 0; // Convert to 32bit integer
122+
}
123+
return hash;
124+
};
125+
126+
// Faces from uifaces.com. Thanks!
127+
var faces = [
128+
"https://s3.amazonaws.com/uifaces/faces/twitter/jsa/128.jpg",
129+
"https://s3.amazonaws.com/uifaces/faces/twitter/sauro/128.jpg",
130+
"https://s3.amazonaws.com/uifaces/faces/twitter/brad_frost/128.jpg",
131+
"https://s3.amazonaws.com/uifaces/faces/twitter/rem/128.jpg",
132+
"https://s3.amazonaws.com/uifaces/faces/twitter/pixeliris/128.jpg",
133+
"https://s3.amazonaws.com/uifaces/faces/twitter/csswizardry/128.jpg",
134+
];
135+
136+
return faces[hashString(string) % faces.length];
137+
}

demos/credential-management/style.css

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
body {
2+
margin: 0 auto;
3+
width: 500px;
4+
}
5+
header {
6+
background: #EEE;
7+
display: flex;
8+
}
9+
h1 {
10+
font: 700 30px/1 sans-serif;
11+
font-weight: bold;
12+
margin: 0;
13+
padding: 0.25em;
14+
flex: 1 1 auto;
15+
}
16+
header button {
17+
font: 700 15px/30px sans-serif;
18+
flex: 1 1 auto;
19+
}
20+
p {
21+
font: 16px/1.2 sans-serif;
22+
text-align: justify;
23+
hyphens: auto;
24+
}
25+
26+
section.signedout, section.signedin {
27+
display: none;
28+
}
29+
30+
.signedout section.signedout {
31+
border: 1px solid #999;
32+
background: #FF6666;
33+
margin: 0.25em 0;
34+
padding: 1em;
35+
display: block;
36+
}
37+
38+
.signedin section.signedin {
39+
border: 1px solid #999;
40+
background: #66FF66;
41+
margin: 0.25em 0;
42+
padding: 1em;
43+
display: block;
44+
}
45+
46+
label, input {
47+
display: block;
48+
margin: 0;
49+
font: 700 15px/30px sans-serif;
50+
}
51+
52+
input[type=submit] {
53+
margin-top: 0.5em;
54+
}

specs/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ CSP2-PR: CSP2/published/2015-08-PR.html
1717
CSP3: content-security-policy/index.html
1818
EPR: epr/index.html
1919
MIX: mixedcontent/index.html
20-
MIX-CR: mixedcontent/published/2015-08-CR.html
20+
MIX-CR: mixedcontent/published/2015-09-CR.html
2121
MIX-PR: mixedcontent/published/2015-07-PR.html
2222
POWER: powerfulfeatures/index.html
2323
POWER-WD: powerfulfeatures/published/WD.html
@@ -61,8 +61,8 @@ mixedcontent/index.html: mixedcontent/index.src.html biblio.json
6161
mixedcontent/published/2015-07-PR.html: mixedcontent/index.src.html
6262
bikeshed -f spec --md-status=PR --md-date=2015-07-01 --md-deadline=2015-08-01 ./mixedcontent/index.src.html ./mixedcontent/published/2015-07-PR.html
6363

64-
mixedcontent/published/2015-08-CR.html: mixedcontent/index.src.html
65-
bikeshed -f spec --md-status=CR --md-date=2015-08-04 --md-deadline=2015-09-04 ./mixedcontent/index.src.html ./mixedcontent/published/2015-08-CR.html
64+
mixedcontent/published/2015-09-CR.html: mixedcontent/index.src.html
65+
bikeshed -f spec --md-status=CR --md-date=2015-09-22 --md-deadline=2015-10-22 ./mixedcontent/index.src.html ./mixedcontent/published/2015-09-CR.html
6666

6767
referrer-policy/index.html: referrer-policy/index.src.html biblio.json
6868
bikeshed -f spec ./referrer-policy/index.src.html

0 commit comments

Comments
 (0)