Removed mentions of "device" from the UI and URLs.

While the intention of the extension specification to OAuth2 for device codes is indeed intended for handling authorisation on devices where the user cannot use any input method on the device,
 it's also very useful for when we want to authorise older devices where there are other difficulties, such as outdated or intentionally omitted root certificates making it only possible to use
 plain HTTP, or just other sorts of applications where having to make a web UI just for receiving the authorisation code to complete the token request would be a bother,
 for me such a case would be bots like Satori.
It essentially just replaces three-legged authorisation from OAuth 1.0a but without the needlessly complex annoying aspects of OAuth 1.0a.

Beyond that I'm also just sick of entering my ridiculously long, randomly generated password letter by letter on the inaccurate touch screen of the Nintendo 3DS.
This commit is contained in:
flash 2024-07-30 13:08:22 +00:00
parent ffb0cb96df
commit 5fa03dd551
5 changed files with 48 additions and 34 deletions

View file

@ -1,4 +1,4 @@
#include device/verify.js #include verify.js
(() => { (() => {
const authoriseButtons = document.querySelectorAll('.js-authorise-action'); const authoriseButtons = document.querySelectorAll('.js-authorise-action');
@ -32,6 +32,6 @@
}; };
} }
if(location.pathname === '/oauth2/device/verify') if(location.pathname === '/oauth2/verify')
HanyuuOAuth2DeviceVerify(); HanyuuOAuth2Verify();
})(); })();

View file

@ -4,7 +4,7 @@
#include header/header.js #include header/header.js
#include header/user.jsx #include header/user.jsx
const HanyuuOAuth2DeviceVerify = () => { const HanyuuOAuth2Verify = () => {
const queryParams = new URLSearchParams(window.location.search); const queryParams = new URLSearchParams(window.location.search);
const loading = new HanyuuOAuth2Loading('.js-loading'); const loading = new HanyuuOAuth2Loading('.js-loading');
const header = new HanyuuOAuth2Header; const header = new HanyuuOAuth2Header;
@ -18,27 +18,34 @@ const HanyuuOAuth2DeviceVerify = () => {
let userCode = ''; let userCode = '';
let userHeader; let userHeader;
const verifyDeviceRequest = async approve => { const verifyAuthsRequest = async approve => {
return await $x.post('/oauth2/device/verify', { type: 'json' }, { return await $x.post('/oauth2/verify', { type: 'json' }, {
_csrfp: HanyuuCSRFP.getToken(), _csrfp: HanyuuCSRFP.getToken(),
code: userCode, code: userCode,
approve: approve === true ? 'yes' : 'no', approve: approve === true ? 'yes' : 'no',
}); });
}; };
const handleVerifyDeviceResponse = result => { const handleVerifyAuthsResponse = result => {
const response = result.body(); const response = result.body();
if(!response || typeof response.error === 'string') { if(!response) {
alert('Request to verify endpoint failed. Please try again.');
loading.visible = false;
fAuths.classList.remove('hidden');
return;
}
if(typeof response.error === 'string') {
// TODO: nicer errors // TODO: nicer errors
if(response.error === 'auth') if(response.error === 'auth')
alert('You are not logged in.'); alert('You are not logged in.');
else if(response.error === 'csrf') else if(response.error === 'csrf')
alert('Request verification failed, please refresh and try again.'); alert('Request verification failed, please refresh and try again.');
else if(response.error === 'code') else if(response.error === 'code')
alert('This code is not associated with any device authorisation request.'); alert('This code is not associated with any authorisation request.');
else if(response.error === 'approval') else if(response.error === 'approval')
alert('The device authorisation request associated with this code is not pending approval.'); alert('The authorisation request associated with this code is not pending approval.');
else if(response.error === 'invalid') else if(response.error === 'invalid')
alert('Invalid approval state specified.'); alert('Invalid approval state specified.');
else else
@ -65,8 +72,8 @@ const HanyuuOAuth2DeviceVerify = () => {
if(userHeader) if(userHeader)
userHeader.guiseVisible = false; userHeader.guiseVisible = false;
verifyDeviceRequest(ev.submitter.value === 'yes') verifyAuthsRequest(ev.submitter.value === 'yes')
.then(handleVerifyDeviceResponse); .then(handleVerifyAuthsResponse);
}; };
const fCode = document.querySelector('.js-verify-code'); const fCode = document.querySelector('.js-verify-code');
@ -78,20 +85,27 @@ const HanyuuOAuth2DeviceVerify = () => {
loading.visible = true; loading.visible = true;
fCode.classList.add('hidden'); fCode.classList.add('hidden');
$x.get(`/oauth2/device/resolve?csrfp=${encodeURIComponent(HanyuuCSRFP.getToken())}&code=${encodeURIComponent(eUserCode.value)}`, { type: 'json' }) $x.get(`/oauth2/resolve-request?csrfp=${encodeURIComponent(HanyuuCSRFP.getToken())}&code=${encodeURIComponent(eUserCode.value)}`, { type: 'json' })
.then(result => { .then(result => {
const response = result.body(); const response = result.body();
if(!response || typeof response.error === 'string') { if(!response) {
alert('Request to resolve endpoint failed. Please try again.');
loading.visible = false;
fCode.classList.remove('hidden');
return;
}
if(typeof response.error === 'string') {
// TODO: nicer errors // TODO: nicer errors
if(response.error === 'auth') if(response.error === 'auth')
alert('You are not logged in.'); alert('You are not logged in.');
else if(response.error === 'csrf') else if(response.error === 'csrf')
alert('Request verification failed, please refresh and try again.'); alert('Request verification failed, please refresh and try again.');
else if(response.error === 'code') else if(response.error === 'code')
alert('This code is not associated with any device authorisation request.'); alert('This code is not associated with any authorisation request.');
else if(response.error === 'approval') else if(response.error === 'approval')
alert('The device authorisation request associated with this code is not pending approval.'); alert('The authorisation request associated with this code is not pending approval.');
else else
alert(`An unknown error occurred: ${response.error}`); alert(`An unknown error occurred: ${response.error}`);
@ -100,7 +114,7 @@ const HanyuuOAuth2DeviceVerify = () => {
return; return;
} }
userCode = response.device.code; userCode = response.req.code;
userHeader = new HanyuuOAuth2UserHeader(response.user); userHeader = new HanyuuOAuth2UserHeader(response.user);
header.setElement(userHeader); header.setElement(userHeader);
@ -109,7 +123,7 @@ const HanyuuOAuth2DeviceVerify = () => {
if(userHeader) if(userHeader)
userHeader.guiseVisible = false; userHeader.guiseVisible = false;
verifyDeviceRequest(true).then(handleVerifyDeviceResponse); verifyAuthsRequest(true).then(handleVerifyAuthsResponse);
return; return;
} }

View file

@ -7,7 +7,7 @@ site:name Hanyuu
misuzu:endpoint http://msz.local misuzu:endpoint http://msz.local
misuzu:secret beans misuzu:secret beans
oauth2:device:verification_uri https://hau.local/oauth2/device oauth2:device:verification_uri https://hau.local/oauth2/verify
oauth2:device:verification_uri_complete https://hau.local/oauth2/device?code=%s oauth2:device:verification_uri_complete https://hau.local/oauth2/verify?code=%s
csrfp:secret change this please csrfp:secret change this please

View file

@ -378,8 +378,8 @@ final class OAuth2Routes extends RouteHandler {
]; ];
} }
#[HttpGet('/oauth2/device/verify')] #[HttpGet('/oauth2/verify')]
public function getDeviceVerify($response, $request) { public function getVerify($response, $request) {
$authInfo = ($this->getAuthInfo)(); $authInfo = ($this->getAuthInfo)();
if(!isset($authInfo->user)) if(!isset($authInfo->user))
return $this->templating->render('oauth2/login', [ return $this->templating->render('oauth2/login', [
@ -388,13 +388,13 @@ final class OAuth2Routes extends RouteHandler {
$csrfp = new CSRFP(($this->getCSRFPSecret)(), $authInfo->session->token); $csrfp = new CSRFP(($this->getCSRFPSecret)(), $authInfo->session->token);
return $this->templating->render('oauth2/device/verify', [ return $this->templating->render('oauth2/verify', [
'csrfp_token' => $csrfp->createToken(), 'csrfp_token' => $csrfp->createToken(),
]); ]);
} }
#[HttpPost('/oauth2/device/verify')] #[HttpPost('/oauth2/verify')]
public function postDeviceVerify($response, $request) { public function postVerify($response, $request) {
if(!$request->isFormContent()) if(!$request->isFormContent())
return 400; return 400;
@ -432,8 +432,8 @@ final class OAuth2Routes extends RouteHandler {
]; ];
} }
#[HttpGet('/oauth2/device/resolve')] #[HttpGet('/oauth2/resolve-request')]
public function getDeviceResolve($response, $request) { public function getResolveRequest($response, $request) {
// TODO: RATE LIMITING // TODO: RATE LIMITING
$authInfo = ($this->getAuthInfo)(); $authInfo = ($this->getAuthInfo)();
@ -462,7 +462,7 @@ final class OAuth2Routes extends RouteHandler {
} }
$result = [ $result = [
'device' => [ 'req' => [
'code' => $deviceInfo->getUserCode(), 'code' => $deviceInfo->getUserCode(),
], ],
'app' => [ 'app' => [
@ -493,8 +493,8 @@ final class OAuth2Routes extends RouteHandler {
return $result; return $result;
} }
#[HttpPost('/oauth2/device/authorise')] #[HttpPost('/oauth2/request-authorise')]
public function postDeviceAuthorise($response, $request) { public function postRequestAuthorise($response, $request) {
$response->setHeader('Cache-Control', 'no-store'); $response->setHeader('Cache-Control', 'no-store');
if(!$request->isFormContent()) { if(!$request->isFormContent()) {

View file

@ -1,8 +1,8 @@
{% extends 'oauth2/master.twig' %} {% extends 'oauth2/master.twig' %}
{% set body_header_class = 'devicehead' %} {% set body_header_class = 'devicehead' %}
{% set body_header_text = 'Device authorisation' %} {% set body_header_text = 'Code authorisation' %}
{% set body_title = 'Device Authorisation Request' %} {% set body_title = 'Authorisation Request' %}
{% block body_content %} {% block body_content %}
<div class="js-loading"></div> <div class="js-loading"></div>
@ -41,7 +41,7 @@
<div class="oauth2-approval-icon oauth2-approval-icon-approved"></div> <div class="oauth2-approval-icon oauth2-approval-icon-approved"></div>
<div class="oauth2-approval-header">Approved!</div> <div class="oauth2-approval-header">Approved!</div>
<div class="oauth2-approval-text"> <div class="oauth2-approval-text">
<p>You have approved the device authorisation request. You should now be signed in on the target device or application.</p> <p>You have approved the authorisation request. You should now be signed in on the target device or application.</p>
</div> </div>
</div> </div>
</div> </div>
@ -51,7 +51,7 @@
<div class="oauth2-approval-icon oauth2-approval-icon-denied"></div> <div class="oauth2-approval-icon oauth2-approval-icon-denied"></div>
<div class="oauth2-approval-header">Denied!</div> <div class="oauth2-approval-header">Denied!</div>
<div class="oauth2-approval-text"> <div class="oauth2-approval-text">
<p>You have denied the device authorisation request. Please return to the target device or application and follow displayed instructions.</p> <p>You have denied the authorisation request. Please return to the target device or application and follow displayed instructions.</p>
</div> </div>
</div> </div>
</div> </div>