mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Alert on new session creation
This commit is contained in:
@@ -98,7 +98,9 @@ _APP_VCS_GITHUB_CLIENT_SECRET=
|
||||
_APP_VCS_GITHUB_WEBHOOK_SECRET=
|
||||
_APP_MIGRATIONS_FIREBASE_CLIENT_ID=
|
||||
_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET=
|
||||
_APP_ASSISTANT_OPENAI_API_KEY=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
|
||||
_APP_ASSISTANT_OPENAI_API_KEY=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
|
||||
_APP_MESSAGE_SMS_TEST_DSN=
|
||||
_APP_MESSAGE_EMAIL_TEST_DSN=
|
||||
_APP_MESSAGE_PUSH_TEST_DSN=
|
||||
_APP_CONSOLE_SUPABASE_APP_ID=d64cd75f-2786-4b94-aeda-eae01e165941
|
||||
_APP_CONSOLE_SUPABASE_SECRET=sba_d5a802fbdcdf86d27f7d071a2778bff0419040de
|
||||
|
||||
@@ -207,7 +207,7 @@ return [
|
||||
],
|
||||
Exception::USER_PASSWORD_AI => [
|
||||
'name' => Exception::USER_PASSWORD_AI,
|
||||
'description' => 'AI does not like security of the password you are trying to use. For your security, please choose a different password and try again.',
|
||||
'description' => 'As per AI, your password is as strong as Grandior wifi. Please choose a different password and try again.',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::USER_SESSION_NOT_FOUND => [
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
<a href="{{redirect}}" target="_blank">{{redirect}}</a>
|
||||
|
||||
<b>{{code}}</b>
|
||||
|
||||
<p>{{footer}}</p>
|
||||
|
||||
<br>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"emails.magicSession.subject": "Login",
|
||||
"emails.magicSession.hello": "Hey,",
|
||||
"emails.magicSession.body": "Follow this link to login.",
|
||||
"emails.magicSession.codeBody": "Enter this code to login.",
|
||||
"emails.magicSession.footer": "If you didn’t ask to login using this email, you can ignore this message.",
|
||||
"emails.magicSession.thanks": "Thanks",
|
||||
"emails.magicSession.signature": "{{project}} team",
|
||||
|
||||
@@ -152,6 +152,16 @@ return [
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'supabase' => [
|
||||
'name' => 'Supabase',
|
||||
'developers' => 'https://supabase.com/docs',
|
||||
'icon' => 'icon-supabase',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'gitlab' => [
|
||||
'name' => 'GitLab',
|
||||
'developers' => 'https://docs.gitlab.com/ee/api/',
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1014,7 +1014,8 @@ App::post('/v1/account/sessions/magic-url')
|
||||
->label('abuse-key', 'url:{url},email:{param-email}')
|
||||
->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('email', '', new Email(), 'User email.')
|
||||
->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
|
||||
->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
|
||||
->param('type', 'link', new WhiteList(['link', 'code']), 'The type of verification email to be sent. ', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
@@ -1023,7 +1024,7 @@ App::post('/v1/account/sessions/magic-url')
|
||||
->inject('locale')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForMails')
|
||||
->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails) {
|
||||
->action(function (string $userId, string $email, string $url, string $type, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails) {
|
||||
|
||||
if (empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled');
|
||||
@@ -1088,6 +1089,14 @@ App::post('/v1/account/sessions/magic-url')
|
||||
$loginSecret = Auth::tokenGenerator();
|
||||
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_CONFIRM));
|
||||
|
||||
if ($type === 'code') {
|
||||
$loginSecret = Auth::codeGenerator();
|
||||
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_PHONE));
|
||||
} else if($type === 'link') {
|
||||
$loginSecret = Auth::tokenGenerator();
|
||||
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_CONFIRM));
|
||||
}
|
||||
|
||||
$token = new Document([
|
||||
'$id' => ID::unique(),
|
||||
'userId' => $user->getId(),
|
||||
@@ -1118,7 +1127,7 @@ App::post('/v1/account/sessions/magic-url')
|
||||
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $user->getId(), 'secret' => $loginSecret, 'expire' => $expire, 'project' => $project->getId()]);
|
||||
$url = Template::unParseURL($url);
|
||||
|
||||
$body = $locale->getText("emails.magicSession.body");
|
||||
$body = $type === 'code' ? $locale->getText("emails.magicSession.codeBody") : $locale->getText("emails.magicSession.body");
|
||||
$subject = $locale->getText("emails.magicSession.subject");
|
||||
$customTemplate = $project->getAttribute('templates', [])['email.magicSession-' . $locale->default] ?? [];
|
||||
|
||||
@@ -1183,7 +1192,8 @@ App::post('/v1/account/sessions/magic-url')
|
||||
'user' => '',
|
||||
'team' => '',
|
||||
'project' => $project->getAttribute('name'),
|
||||
'redirect' => $url
|
||||
'redirect' => $type === 'link' ? $url : '',
|
||||
'code' => $type === 'code' ? $loginSecret : '',
|
||||
];
|
||||
|
||||
$queueForMails
|
||||
@@ -2138,6 +2148,13 @@ App::patch('/v1/account/password')
|
||||
}
|
||||
}
|
||||
|
||||
if ($project->getAttribute('auths', [])['passwordAi'] ?? false) {
|
||||
$passwordAiValidator = new PasswordAi();
|
||||
if (!$passwordAiValidator->isValid($password)) {
|
||||
throw new Exception(Exception::USER_PASSWORD_AI);
|
||||
}
|
||||
}
|
||||
|
||||
if ($project->getAttribute('auths', [])['passwordDictionary'] ?? false) {
|
||||
$passwordDictionaryLength = $project->getAttribute('auths', [])['passwordDictionaryLength'] ?? '10k';
|
||||
if ($passwordDictionaryLength == '10k') {
|
||||
|
||||
@@ -85,7 +85,7 @@ App::post('/v1/projects')
|
||||
}
|
||||
|
||||
$auth = Config::getParam('auth', []);
|
||||
$auths = ['limit' => 0, 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT, 'passwordHistory' => 0, 'passwordAi' => false, 'sessionRefresh' => false, 'passwordDictionary' => false, 'passwordDictionaryLength' => '10k', 'notify' => true, 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, 'personalDataCheck' => false];
|
||||
$auths = ['limit' => 0, 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT, 'passwordHistory' => 0, 'passwordAi' => false, 'renewal' => false, 'passwordDictionary' => false, 'passwordDictionaryLength' => '10k', 'notify' => false, 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, 'personalDataCheck' => false];
|
||||
foreach ($auth as $index => $method) {
|
||||
$auths[$method['key'] ?? ''] = true;
|
||||
}
|
||||
@@ -674,9 +674,10 @@ App::patch('/v1/projects/:projectId/auth/duration')
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('duration', 31536000, new Range(0, 31536000), 'Project session length in seconds. Max length: 31536000 seconds.')
|
||||
->param('renewal', false, new Boolean(), 'Automatic session refresh. If enabled, sessions are automatically extended to session duration on every request.', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, int $duration, Response $response, Database $dbForConsole) {
|
||||
->action(function (string $projectId, int $duration, bool $renewal, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
@@ -686,37 +687,7 @@ App::patch('/v1/projects/:projectId/auth/duration')
|
||||
|
||||
$auths = $project->getAttribute('auths', []);
|
||||
$auths['duration'] = $duration;
|
||||
|
||||
$dbForConsole->updateDocument('projects', $project->getId(), $project
|
||||
->setAttribute('auths', $auths));
|
||||
|
||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||
});
|
||||
|
||||
App::patch('/v1/projects/:projectId/auth/session-refresh')
|
||||
->desc('Update project session refresh')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'projects')
|
||||
->label('sdk.method', 'updateSessionRefresh')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('sessionRefresh', false, new Boolean(), 'Automatic session refresh. If enabled, sessions are automatically extended to session duration on every request.', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, int $sessionRefresh, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$auths = $project->getAttribute('auths', []);
|
||||
$auths['sessionRefresh'] = $sessionRefresh;
|
||||
$auths['renewal'] = $renewal;
|
||||
|
||||
$dbForConsole->updateDocument('projects', $project->getId(), $project
|
||||
->setAttribute('auths', $auths));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Auth\Validator\Password;
|
||||
use Appwrite\Auth\Validator\PasswordAi;
|
||||
use Appwrite\Auth\Validator\Phone;
|
||||
use Appwrite\Detector\Detector;
|
||||
use Appwrite\Event\Delete;
|
||||
@@ -71,6 +72,13 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
|
||||
}
|
||||
}
|
||||
|
||||
if ($project->getAttribute('auths', [])['passwordAi'] ?? false) {
|
||||
$passwordAiValidator = new PasswordAi();
|
||||
if (!$passwordAiValidator->isValid($password)) {
|
||||
throw new Exception(Exception::USER_PASSWORD_AI);
|
||||
}
|
||||
}
|
||||
|
||||
$password = (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null;
|
||||
$user = $dbForProject->createDocument('users', new Document([
|
||||
'$id' => $userId,
|
||||
@@ -1114,6 +1122,13 @@ App::patch('/v1/users/:userId/password')
|
||||
throw new Exception(Exception::USER_PASSWORD_PERSONAL_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
if ($project->getAttribute('auths', [])['passwordAi'] ?? false) {
|
||||
$passwordAiValidator = new PasswordAi();
|
||||
if (!$passwordAiValidator->isValid($password)) {
|
||||
throw new Exception(Exception::USER_PASSWORD_AI);
|
||||
}
|
||||
}
|
||||
|
||||
if ($project->getAttribute('auths', [])['passwordDictionary'] ?? false) {
|
||||
$passwordDictionaryLength = $project->getAttribute('auths', [])['passwordDictionaryLength'] ?? '10k';
|
||||
|
||||
@@ -172,7 +172,7 @@ App::init()
|
||||
/*
|
||||
* Session refresh
|
||||
*/
|
||||
if ($project->getAttribute('auths', [])['sessionRefresh'] ?? false) {
|
||||
if ($project->getAttribute('auths', [])['renewal'] ?? false) {
|
||||
if ($user && !$user->isEmpty()) {
|
||||
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||
$currentSessionId = Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret, $authDuration);
|
||||
|
||||
+6
-1
@@ -175,6 +175,8 @@ const COMPRESSION_TYPE_NONE = 'none';
|
||||
const COMPRESSION_TYPE_GZIP = 'gzip';
|
||||
const COMPRESSION_TYPE_ZSTD = 'zstd';
|
||||
// Mail Types
|
||||
const MAIL_TYPE_VERIFICATION_URL = 'verificationUrl';
|
||||
const MAIL_TYPE_VERIFICATION_CODE = 'verificationCode';
|
||||
const MAIL_TYPE_VERIFICATION = 'verification';
|
||||
const MAIL_TYPE_MAGIC_SESSION = 'magicSession';
|
||||
const MAIL_TYPE_RECOVERY = 'recovery';
|
||||
@@ -1231,7 +1233,10 @@ App::setResource('console', function () {
|
||||
'oAuthProviders' => [
|
||||
'githubEnabled' => true,
|
||||
'githubSecret' => App::getEnv('_APP_CONSOLE_GITHUB_SECRET', ''),
|
||||
'githubAppid' => App::getEnv('_APP_CONSOLE_GITHUB_APP_ID', '')
|
||||
'githubAppid' => App::getEnv('_APP_CONSOLE_GITHUB_APP_ID', ''),
|
||||
'supabaseEnabled' => true,
|
||||
'supabaseSecret' => App::getEnv('_APP_CONSOLE_SUPABASE_SECRET', ''),
|
||||
'supabaseAppid' => App::getEnv('_APP_CONSOLE_SUPABASE_APP_ID', ''),
|
||||
],
|
||||
]);
|
||||
}, []);
|
||||
|
||||
@@ -191,6 +191,8 @@ services:
|
||||
- _APP_MESSAGE_SMS_TEST_DSN
|
||||
- _APP_MESSAGE_EMAIL_TEST_DSN
|
||||
- _APP_MESSAGE_PUSH_TEST_DSN
|
||||
- _APP_CONSOLE_SUPABASE_SECRET
|
||||
- _APP_CONSOLE_SUPABASE_APP_ID
|
||||
appwrite-realtime:
|
||||
entrypoint: realtime
|
||||
<<: *x-logging
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
|
||||
// Reference Material
|
||||
// https://supabase.com/docs/guides/platform/oauth-apps/build-a-supabase-integration
|
||||
|
||||
class Supabase extends OAuth2
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $endpoint = 'https://api.supabase.com/v1';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'supabase';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint . '/oauth/authorize?' .
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback
|
||||
]);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
])
|
||||
), true);
|
||||
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://discord.com/developers/docs/resources/user
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['verified'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
return $user['username'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
$this->endpoint . '/organizations',
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
);
|
||||
\var_dump($user);
|
||||
$this->user = \json_decode($user, true);
|
||||
$this->user = [
|
||||
'username' => $this->user[0]['name'],
|
||||
'verified' => false,
|
||||
'email' => $this->user[0]['name'] . '@supabase.internal',
|
||||
'id' => $this->user[0]['id']
|
||||
];
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ class Users extends Base
|
||||
'email',
|
||||
'phone',
|
||||
'status',
|
||||
'hash',
|
||||
'passwordUpdate',
|
||||
'registration',
|
||||
'emailVerification',
|
||||
|
||||
@@ -133,7 +133,7 @@ class Project extends Model
|
||||
'example' => true,
|
||||
])
|
||||
->addRule('authPasswordDictionaryLength', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'How many most commonly used password to check against. Possible values are: 10k, 100k, 1m, 10m',
|
||||
'default' => '10k',
|
||||
'example' => '1m',
|
||||
@@ -156,6 +156,18 @@ class Project extends Model
|
||||
'default' => false,
|
||||
'example' => true,
|
||||
])
|
||||
->addRule('authPasswordAi', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Whether or not to check user\'s password against against AI opinion',
|
||||
'default' => false,
|
||||
'example' => true,
|
||||
])
|
||||
->addRule('authRenewal', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Whether or not sessions are automatically extended to session duration on every request',
|
||||
'default' => false,
|
||||
'example' => true,
|
||||
])
|
||||
->addRule('authPersonalDataCheck', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Whether or not to check the user password for similarity with their personal data.',
|
||||
@@ -344,7 +356,7 @@ class Project extends Model
|
||||
$document->setAttribute('authPasswordDictionaryLength', $authValues['passwordDictionaryLength'] ?? false);
|
||||
$document->setAttribute('authPasswordAi', $authValues['passwordAi'] ?? false);
|
||||
$document->setAttribute('authNotify', $authValues['notify'] ?? false);
|
||||
$document->setAttribute('authSessionRefresh', $authValues['sessionRefresh'] ?? false);
|
||||
$document->setAttribute('authRenewal', $authValues['renewal'] ?? false);
|
||||
$document->setAttribute('authPersonalDataCheck', $authValues['personalDataCheck'] ?? false);
|
||||
|
||||
foreach ($auth as $index => $method) {
|
||||
|
||||
Reference in New Issue
Block a user