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',
|
'docs' => 'https://appwrite.io/docs/client/account?sdk=web#accountCreateSession',
|
||||||
'enabled' => true,
|
'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' => [
|
'anonymous' => [
|
||||||
'name' => 'Anonymous',
|
'name' => 'Anonymous',
|
||||||
'key' => 'usersAuthAnonymous',
|
'key' => 'usersAuthAnonymous',
|
||||||
|
|
|
@ -616,6 +616,7 @@ App::post('/v1/account/sessions/magic-url')
|
||||||
->desc('Create Magic URL session')
|
->desc('Create Magic URL session')
|
||||||
->groups(['api', 'account'])
|
->groups(['api', 'account'])
|
||||||
->label('scope', 'public')
|
->label('scope', 'public')
|
||||||
|
->label('auth.type', 'magic-url')
|
||||||
->label('sdk.auth', [])
|
->label('sdk.auth', [])
|
||||||
->label('sdk.namespace', 'account')
|
->label('sdk.namespace', 'account')
|
||||||
->label('sdk.method', 'createMagicURLSession')
|
->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);
|
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 = 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);
|
$url = Template::unParseURL($url);
|
||||||
|
|
||||||
$mails
|
$mails
|
||||||
|
@ -849,6 +854,10 @@ App::put('/v1/account/sessions/magic-url')
|
||||||
if (false === $user) {
|
if (false === $user) {
|
||||||
throw new Exception('Failed saving user to DB', 500);
|
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
|
$audits
|
||||||
->setParam('userId', $user->getId())
|
->setParam('userId', $user->getId())
|
||||||
|
|
|
@ -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')
|
App::get('/auth/oauth2/failure')
|
||||||
->groups(['web', 'home'])
|
->groups(['web', 'home'])
|
||||||
->label('permission', 'public')
|
->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,
|
template: "/auth/join?version=" + APP_ENV.CACHEBUSTER,
|
||||||
scope: "home"
|
scope: "home"
|
||||||
})
|
})
|
||||||
|
.add("/auth/magic-url", {
|
||||||
|
template: "/auth/magic-url?version=" + APP_ENV.CACHEBUSTER,
|
||||||
|
scope: "home"
|
||||||
|
})
|
||||||
.add("/auth/oauth2/success", {
|
.add("/auth/oauth2/success", {
|
||||||
template: "/auth/oauth2/success?version=" + APP_ENV.CACHEBUSTER,
|
template: "/auth/oauth2/success?version=" + APP_ENV.CACHEBUSTER,
|
||||||
scope: "home"
|
scope: "home"
|
||||||
|
|
|
@ -1157,4 +1157,130 @@ trait AccountBase
|
||||||
|
|
||||||
return $data;
|
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