Last active
June 26, 2018 12:59
-
-
Save Terrance/e0b2a0ebbff3c9ca98a6f9a405ccf835 to your computer and use it in GitHub Desktop.
Alternative single-HTML-file Monzo login page, a drop-in replacement for https://auth.monzo.com.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Monzo account access</title> | |
<link | |
rel="stylesheet" | |
href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css" | |
integrity="sha256-zIG416V1ynj3Wgju/scU80KAEWOsO5rRLfVyRDuOv7Q=" | |
crossorigin="anonymous"> | |
<style> | |
html { | |
overflow-y: auto; | |
} | |
body { | |
background-color: #ff3860; | |
} | |
#fixed { | |
max-width: 768px; | |
margin-left: auto; | |
margin-right: auto; | |
padding: 0; | |
overflow: hidden; | |
} | |
.section { | |
padding: 1.5rem; | |
} | |
.content:not(:last-child) { | |
margin-bottom: 0; | |
} | |
.upper { | |
background-color: #363636; | |
} | |
.upper .title { | |
color: #f5f5f5; | |
} | |
.lower { | |
background-color: #f5f5f5; | |
} | |
#error { | |
background-color: #ffdd57; | |
} | |
.raw { | |
margin-top: 1.5rem; | |
} | |
#error, #info, #login, #done, .raw:empty { | |
display: none; | |
} | |
</style> | |
</head> | |
<body> | |
<section class="hero is-fullheight"> | |
<div class="hero-body"> | |
<div class="container"> | |
<div id="fixed" class="box"> | |
<div class="section upper"> | |
<h1 class="title">Monzo account access</h1> | |
</div> | |
<div id="loading" class="section lower"> | |
<p>Just a moment...</p> | |
</div> | |
<div id="info" class="section content"> | |
<h2 id="info-name" class="subtitle"></h2> | |
<blockquote id="info-description"></blockquote> | |
<p>This app will be able to:</p> | |
<ul id="info-scope-descriptions"></ul> | |
<pre id="info-raw" class="raw"></pre> | |
</div> | |
<div id="error" class="section content"> | |
<div id="error-list"></div> | |
<pre id="error-raw" class="raw"></pre> | |
</div> | |
<div id="login" class="section lower"> | |
<form class="columns"> | |
<div class="column is-8"> | |
<input id="login-email" type="email" class="input" placeholder="Email address" required> | |
</div> | |
<div class="column"> | |
<button id="login-submit" type="submit" class="button is-fullwidth is-danger">Authorise</button> | |
</div> | |
</form> | |
<p id="login-redirect">After confirming the login via email, you will be redirected to <span id="login-domain"></span>.</p> | |
</div> | |
<div id="done" class="section lower"> | |
<p>Check your email at <span id="done-email"></span> to continue. You can now close this page.</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</section> | |
<script | |
src="https://code.jquery.com/jquery-3.3.1.min.js" | |
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" | |
crossorigin="anonymous"></script> | |
<script> | |
"use strict"; | |
$(document).ready(function() { | |
function query() { | |
let data = {}; | |
for (var kv of location.search.substring(1).split("&")) { | |
let split = kv.split("="); | |
let k = decodeURIComponent(split.shift()); | |
let v = decodeURIComponent(split.join("=")); | |
data[k] = v; | |
} | |
if (!("raw" in data)) { | |
$(".raw").hide(); | |
} | |
return data; | |
} | |
var err_strings = { | |
missing: { | |
"response_type": "<code>response_type</code> must be set to <code>\"code\"</code>.", | |
"client_id": "<code>client_id</code> must be specified.", | |
"redirect_uri": "<code>redirect_uri</code> must be specified." | |
}, | |
invalid: { | |
"redirect_uri": "<code>redirect_uri</code> differs between the client and the request." | |
}, | |
lookup: { | |
"not_found.client": "No application exists for the given client ID.", | |
"internal_service": "An unknown error occurred whilst submitting your request." | |
}, | |
auth: { | |
"bad_request.client_not_found": "No application exists for the given client ID.", | |
"bad_request.bad_param.redirect_uri": "<code>redirect_uri</code> isn't specified, or differs between the client and the request.", | |
"bad_request.bad_param.recipient_email": "The email address you entered doesn't belong to a Monzo account.", | |
"bad_request.client_not_published": "The application you're authorising is not public, and you're not whitelisted as a collaborator.", | |
"internal_service": "An unknown error occurred whilst submitting your request." | |
} | |
}; | |
function lookup(query, success, failed) { | |
let errors = []; | |
if (query.response_type !== "code") { | |
errors.push(err_strings.missing.response_type); | |
} | |
if (!query.client_id) { | |
errors.push(err_strings.missing.client_id); | |
} | |
if (!query.redirect_uri) { | |
errors.push(err_strings.missing.redirect_uri); | |
} | |
if (errors.length) { | |
failed(errors); | |
return; | |
} | |
$.ajax({ | |
url: "https://api.monzo.com/oauth2/clients/" + encodeURIComponent(query.client_id), | |
statusCode: { | |
200: function(data) { | |
if (data.redirect_uri !== query.redirect_uri) { | |
failed([err_strings.invalid.redirect_uri, | |
"Client: <code>" + data.redirect_uri + "</code><br>Request: <code>" + query.redirect_uri + "</code>"], data); | |
} else { | |
success(data); | |
} | |
}, | |
404: function(data) { | |
failed([err_strings.lookup[data.responseJSON.code] || data.responseJSON.message], data.responseJSON); | |
}, | |
500: function(data) { | |
failed([err_strings.lookup[data.responseJSON.code] || data.responseJSON.message], data.responseJSON); | |
} | |
}, | |
error: function(jqXHR, status, error) { | |
if (status !== "error" && error !== "Not Found") { | |
failed([err_strings.lookup.internal_service]); | |
} | |
} | |
}); | |
} | |
function auth(query, email, success, failed) { | |
$("#error").hide(); | |
$("#login-email").prop("disabled", true); | |
$("#login-submit").addClass("is-loading"); | |
$.ajax({ | |
method: "post", | |
url: "https://api.monzo.com/oauth2/authorize", | |
data: { | |
client_id: query.client_id, | |
email: email, | |
redirect_uri: query.redirect_uri, | |
response_type: query.response_type, | |
state: query.state || "" | |
}, | |
statusCode: { | |
200: function(data) { | |
success(email); | |
}, | |
400: function(data) { | |
$("#login-email").prop("disabled", false); | |
$("#login-submit").removeClass("is-loading"); | |
failed([err_strings.auth[data.responseJSON.code] || data.responseJSON.message], data.responseJSON); | |
}, | |
500: function(data) { | |
$("#login-email").prop("disabled", false); | |
$("#login-submit").removeClass("is-loading"); | |
failed([err_strings.auth[data.responseJSON.code] || data.responseJSON.message], data.responseJSON); | |
} | |
}, | |
error: function(jqXHR, status, error) { | |
if (status !== "error" && error !== "Bad Request") { | |
failed([err_strings.lookup.internal_service]); | |
} | |
} | |
}); | |
} | |
function error(errors, data) { | |
$("#error-list").empty(); | |
for (var e of errors) { | |
$("#error-list").append($("<p>").html(e)); | |
} | |
if (data) { | |
$("#error-raw").text(JSON.stringify(data, null, 2)); | |
} | |
$("#loading").hide(); | |
$("#error").show(); | |
} | |
function info(data) { | |
$("#info-name").text(data.name); | |
$("#info-description").text(data.description); | |
for (var s of (data.scope_descriptions || []).concat().sort()) { | |
$("#info-scope-descriptions").append($("<li>").text(s)); | |
} | |
$("#info-raw").text(JSON.stringify(data, null, 2)); | |
try { | |
$("#login-domain").text(new URL(data.redirect_uri).host); | |
} catch (e) { | |
$("#login-redirect").hide(); | |
} | |
$("#loading").hide(); | |
$("#info, #login").show(); | |
$("#login-email").focus(); | |
} | |
function done(email) { | |
$("#done-email").text(email); | |
$("#login").hide(); | |
$("#done").show(); | |
} | |
var data = query(); | |
lookup(data, info, error); | |
$("#login form").submit(function() { | |
auth(data, $("#login-email").val(), done, error); | |
return false; | |
}); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment