updates and fixes, default handler for magic login
This commit is contained in:
parent
4996a80e22
commit
e9e83d14c3
|
@ -10,6 +10,13 @@ return [
|
|||
'docs' => 'https://appwrite.io/docs/client/account?sdk=web#accountCreateSession',
|
||||
'enabled' => true,
|
||||
],
|
||||
'magic-url' => [
|
||||
'name' => 'Magic URL',
|
||||
'key' => 'usersAuthMagicURL',
|
||||
'icon' => '/images/users/magic-url.png',
|
||||
'docs' => 'https://appwrite.io/docs/client/account?sdk=web#accountCreateMagicURLSession',
|
||||
'enabled' => true,
|
||||
],
|
||||
'anonymous' => [
|
||||
'name' => 'Anonymous',
|
||||
'key' => 'usersAuthAnonymous',
|
||||
|
|
|
@ -616,6 +616,7 @@ App::post('/v1/account/sessions/magic-url')
|
|||
->desc('Create Magic URL session')
|
||||
->groups(['api', 'account'])
|
||||
->label('scope', 'public')
|
||||
->label('auth.type', 'magic-url')
|
||||
->label('sdk.auth', [])
|
||||
->label('sdk.namespace', 'account')
|
||||
->label('sdk.method', 'createMagicURLSession')
|
||||
|
@ -730,8 +731,12 @@ App::post('/v1/account/sessions/magic-url')
|
|||
throw new Exception('Failed to save user to DB', 500);
|
||||
}
|
||||
|
||||
if(empty($url)) {
|
||||
$url = $request->getProtocol().'://'.$request->getHostname().'/auth/magic-url/success';
|
||||
}
|
||||
|
||||
$url = Template::parseURL($url);
|
||||
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $user->getId(), 'secret' => $loginSecret, 'expire' => $expire]);
|
||||
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $user->getId(), 'secret' => $loginSecret, 'expire' => $expire, 'project' => $project->getId()]);
|
||||
$url = Template::unParseURL($url);
|
||||
|
||||
$mails
|
||||
|
@ -850,6 +855,10 @@ App::put('/v1/account/sessions/magic-url')
|
|||
throw new Exception('Failed saving user to DB', 500);
|
||||
}
|
||||
|
||||
if (!$projectDB->deleteDocument($token)) {
|
||||
throw new Exception('Failed to remove login token from DB', 500);
|
||||
}
|
||||
|
||||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
->setParam('event', 'account.sessions.create')
|
||||
|
|
|
@ -197,6 +197,35 @@ App::get('/auth/oauth2/success')
|
|||
;
|
||||
});
|
||||
|
||||
App::get('/auth/magic-url')
|
||||
->groups(['web', 'home'])
|
||||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('request')
|
||||
// ->inject('response')
|
||||
->inject('layout')
|
||||
->action(function ($request, $layout) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Utopia\Swoole\Response $response */
|
||||
|
||||
$page = new View(__DIR__.'/../../views/home/auth/magicURL.phtml');
|
||||
|
||||
$userId = $request->getQuery('userId');
|
||||
$secret = $request->getQuery('secret');
|
||||
$project = $request->getQuery('project');
|
||||
$page
|
||||
->setParam('userId', $userId)
|
||||
->setParam('secret', $secret)
|
||||
->setParam('project', $project);
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME)
|
||||
->setParam('body', $page)
|
||||
->setParam('header', [])
|
||||
->setParam('footer', [])
|
||||
;
|
||||
});
|
||||
|
||||
App::get('/auth/oauth2/failure')
|
||||
->groups(['web', 'home'])
|
||||
->label('permission', 'public')
|
||||
|
|
35
app/views/home/auth/magicURL.phtml
Normal file
35
app/views/home/auth/magicURL.phtml
Normal file
|
@ -0,0 +1,35 @@
|
|||
<div class="zone large padding margin-top" id="message" style="display: none">
|
||||
<h1 class="margin-bottom">Missing Redirect URL</h1>
|
||||
<p>Your Magic URL login flow is missing a proper redirect URL. Please check the
|
||||
<a href="https://<?php echo APP_DOMAIN; ?>/docs/client/account?sdk=web#createMagicURLSession">Magic URL docs</a>
|
||||
and send request for new session with a valid redirect URL.</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
setTimeout(function () {
|
||||
document.getElementById('message').style.display = 'block';
|
||||
}, 25);
|
||||
|
||||
<?php echo "var userId = '" . $this->getParam('userId') . "';"; ?>
|
||||
<?php echo "var secret = '" . $this->getParam('secret') . "';"; ?>
|
||||
<?php echo "var project = '" . $this->getParam('project') . "';"; ?>
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('userId', userId);
|
||||
formData.append('secret', secret);
|
||||
|
||||
const res = fetch(window.location.origin + '/v1/account/sessions/magic-url', {
|
||||
method: 'PUT',
|
||||
body: formData,
|
||||
headers: {
|
||||
["x-appwrite-project"]: project
|
||||
}
|
||||
}).then(response => response.json())
|
||||
.then(data => {
|
||||
if(data.$id) {
|
||||
window.location = 'appwrite-callback-' + project + '://'+window.location.search;
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
<hr />
|
2
public/dist/scripts/app-all.js
vendored
2
public/dist/scripts/app-all.js
vendored
File diff suppressed because one or more lines are too long
2
public/dist/scripts/app.js
vendored
2
public/dist/scripts/app.js
vendored
File diff suppressed because one or more lines are too long
BIN
public/images/users/magic-url.png
Normal file
BIN
public/images/users/magic-url.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
|
@ -23,6 +23,10 @@ window.ls.router
|
|||
template: "/auth/join?version=" + APP_ENV.CACHEBUSTER,
|
||||
scope: "home"
|
||||
})
|
||||
.add("/auth/magic-url", {
|
||||
template: "/auth/magic-url?version=" + APP_ENV.CACHEBUSTER,
|
||||
scope: "home"
|
||||
})
|
||||
.add("/auth/oauth2/success", {
|
||||
template: "/auth/oauth2/success?version=" + APP_ENV.CACHEBUSTER,
|
||||
scope: "home"
|
||||
|
|
|
@ -1157,4 +1157,130 @@ trait AccountBase
|
|||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testCreateMagicUrl():array
|
||||
{
|
||||
$email = \time().'user@appwrite.io';
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/magic-url', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
// 'url' => 'http://localhost/magiclogin',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertEmpty($response['body']['secret']);
|
||||
$this->assertIsNumeric($response['body']['expire']);
|
||||
|
||||
$userId = $response['body']['userId'];
|
||||
|
||||
$lastEmail = $this->getLastEmail();
|
||||
$this->assertEquals($email, $lastEmail['to'][0]['address']);
|
||||
$this->assertEquals('Login', $lastEmail['subject']);
|
||||
|
||||
$token = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
|
||||
|
||||
$expireTime = strpos($lastEmail['text'], 'expire='.$response['body']['expire'], 0);
|
||||
|
||||
$this->assertNotFalse($expireTime);
|
||||
|
||||
$secretTest = strpos($lastEmail['text'], 'secret='.$response['body']['secret'], 0);
|
||||
|
||||
$this->assertNotFalse($secretTest);
|
||||
|
||||
$userIDTest = strpos($lastEmail['text'], 'userId='.$response['body']['userId'], 0);
|
||||
|
||||
$this->assertNotFalse($userIDTest);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/magic-url', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'url' => 'localhost/magiclogin',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/magic-url', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'url' => 'http://remotehost/magiclogin',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$data['token'] = $token;
|
||||
$data['id'] = $userId;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateMagicUrl
|
||||
*/
|
||||
public function testCreateSessionWithMagicUrl($data):array
|
||||
{
|
||||
$id = $data['id'] ?? '';
|
||||
$token = $data['token'] ?? '';
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/account/sessions/magic-url', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'userId' => $id,
|
||||
'secret' => $token,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertIsArray($response['body']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertNotEmpty($response['body']['userId']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/account/sessions/magic-url', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'userId' => 'ewewe',
|
||||
'secret' => $token,
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/account/sessions/magic-url', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'userId' => $id,
|
||||
'secret' => 'sdasdasdasd',
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue