Password setup - backend fixes

This commit is contained in:
VakarisZ 2020-06-12 11:50:07 +03:00
parent c8cf7d52a4
commit 889bf359e1
37 changed files with 243 additions and 62 deletions

View File

@ -5,7 +5,7 @@ import flask_restful
from flask import Flask, send_from_directory, Response from flask import Flask, send_from_directory, Response
from werkzeug.exceptions import NotFound from werkzeug.exceptions import NotFound
from monkey_island.cc.auth import init_jwt from monkey_island.cc.resources.auth.auth import init_jwt
from monkey_island.cc.database import mongo, database from monkey_island.cc.database import mongo, database
from monkey_island.cc.environment.environment_singleton import env from monkey_island.cc.environment.environment_singleton import env
from monkey_island.cc.resources.client_run import ClientRun from monkey_island.cc.resources.client_run import ClientRun

View File

@ -5,7 +5,6 @@ from datetime import timedelta
__author__ = 'itay.mizeretz' __author__ = 'itay.mizeretz'
from typing import Dict
from common.utils.exceptions import InvalidRegistrationCredentials from common.utils.exceptions import InvalidRegistrationCredentials
from monkey_island.cc.environment.environment_config import EnvironmentConfig from monkey_island.cc.environment.environment_config import EnvironmentConfig
@ -25,7 +24,7 @@ class Environment(object, metaclass=ABCMeta):
_testing = False _testing = False
def __init__(self): def __init__(self):
self._config = None self._config = EnvironmentConfig("", "", UserCreds())
self._testing = False # Assume env is not for unit testing. self._testing = False # Assume env is not for unit testing.
@property @property
@ -40,6 +39,9 @@ class Environment(object, metaclass=ABCMeta):
def try_add_user(self, credentials: UserCreds): def try_add_user(self, credentials: UserCreds):
if self._credentials_required: if self._credentials_required:
if credentials: if credentials:
if self._is_registered():
raise InvalidRegistrationCredentials("User has already been registered. "
"Reset credentials or login.")
self._config.add_user(credentials) self._config.add_user(credentials)
else: else:
raise InvalidRegistrationCredentials("Missing part of credentials.") raise InvalidRegistrationCredentials("Missing part of credentials.")

View File

@ -1,5 +1,4 @@
import monkey_island.cc.auth from monkey_island.cc.resources.auth.auth_user import User
from monkey_island.cc.auth_user import User
from monkey_island.cc.environment import Environment from monkey_island.cc.environment import Environment
from common.cloud.aws.aws_instance import AwsInstance from common.cloud.aws.aws_instance import AwsInstance

View File

@ -4,9 +4,10 @@ import json
import os import os
from typing import List, Dict from typing import List, Dict
from monkey_island.cc.auth_user import User from monkey_island.cc.resources.auth.auth_user import User
from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH
from monkey_island.cc.environment.user_creds import UserCreds from monkey_island.cc.environment.user_creds import UserCreds
from monkey_island.cc.resources.auth.user_store import UserStore
class EnvironmentConfig: class EnvironmentConfig:
@ -60,6 +61,8 @@ class EnvironmentConfig:
def add_user(self, credentials: UserCreds): def add_user(self, credentials: UserCreds):
self.user_creds = credentials self.user_creds = credentials
self.save_to_file()
UserStore.set_users(self.get_users())
def get_users(self) -> List[User]: def get_users(self) -> List[User]:
auth_user = self.user_creds.to_auth_user() auth_user = self.user_creds.to_auth_user()

View File

@ -1,5 +1,4 @@
from monkey_island.cc.environment import Environment from monkey_island.cc.environment import Environment
import monkey_island.cc.auth
__author__ = 'itay.mizeretz' __author__ = 'itay.mizeretz'
@ -10,6 +9,6 @@ class PasswordEnvironment(Environment):
def get_auth_users(self): def get_auth_users(self):
if self._is_registered(): if self._is_registered():
return self._config.get_users return self._config.get_users()
else: else:
return [] return []

View File

@ -1,4 +1,4 @@
from monkey_island.cc.auth_user import User from monkey_island.cc.resources.auth.auth_user import User
from monkey_island.cc.environment import Environment from monkey_island.cc.environment import Environment
__author__ = 'itay.mizeretz' __author__ = 'itay.mizeretz'

View File

@ -2,8 +2,10 @@ import json
import os import os
from typing import Dict from typing import Dict
from unittest import TestCase from unittest import TestCase
from unittest.mock import patch, MagicMock
from monkey_island.cc.environment import Environment, EnvironmentConfig from common.utils.exceptions import InvalidRegistrationCredentials
from monkey_island.cc.environment import Environment, EnvironmentConfig, UserCreds
def get_server_config_file_path_test_version(): def get_server_config_file_path_test_version():
@ -57,6 +59,21 @@ class TestEnvironment(TestCase):
"4f2e9b3ca9f484f521d0ce464345cc1aec96779149c14" "4f2e9b3ca9f484f521d0ce464345cc1aec96779149c14"
} }
@patch.object(target=EnvironmentConfig, attribute="save_to_file", new=MagicMock())
def test_try_add_user(self):
env = TestEnvironment.EnvironmentWithCredentials()
credentials = UserCreds(username="test", password_hash="1231234")
env.try_add_user(credentials)
credentials = UserCreds(username="test")
with self.assertRaises(InvalidRegistrationCredentials):
env.try_add_user(credentials)
env = TestEnvironment.EnvironmentNoCredentials()
credentials = UserCreds(username="test", password_hash="1231234")
with self.assertRaises(InvalidRegistrationCredentials):
env.try_add_user(credentials)
def test_needs_registration(self): def test_needs_registration(self):
env = TestEnvironment.EnvironmentWithCredentials() env = TestEnvironment.EnvironmentWithCredentials()
self._test_bool_env_method("needs_registration", env, TestEnvironment.CONFIG_WITH_CREDENTIALS, False) self._test_bool_env_method("needs_registration", env, TestEnvironment.CONFIG_WITH_CREDENTIALS, False)

View File

@ -1,4 +1,4 @@
from monkey_island.cc.auth_user import User from monkey_island.cc.resources.auth.auth_user import User
from monkey_island.cc.testing.IslandTestCase import IslandTestCase from monkey_island.cc.testing.IslandTestCase import IslandTestCase
from monkey_island.cc.environment.aws import AwsEnvironment from monkey_island.cc.environment.aws import AwsEnvironment

View File

@ -3,7 +3,7 @@ from __future__ import annotations
import json import json
from typing import Dict from typing import Dict
from monkey_island.cc.auth_user import User from monkey_island.cc.resources.auth.auth_user import User
class UserCreds: class UserCreds:

View File

@ -1,7 +1,7 @@
import flask_restful import flask_restful
from flask import jsonify, request, json, current_app from flask import jsonify, request, json, current_app
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.attack.attack_config import AttackConfig from monkey_island.cc.services.attack.attack_config import AttackConfig
__author__ = "VakarisZ" __author__ = "VakarisZ"

View File

@ -1,5 +1,5 @@
import flask_restful import flask_restful
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.attack.attack_report import AttackReportService from monkey_island.cc.services.attack.attack_report import AttackReportService
from monkey_island.cc.services.attack.attack_schema import SCHEMA from monkey_island.cc.services.attack.attack_schema import SCHEMA
from flask import json, current_app from flask import json, current_app

View File

@ -5,23 +5,22 @@ from flask_jwt import JWT, _jwt_required, JWTError
from werkzeug.security import safe_str_cmp from werkzeug.security import safe_str_cmp
from monkey_island.cc.environment.environment_singleton import env from monkey_island.cc.environment.environment_singleton import env
from monkey_island.cc.resources.auth.user_store import UserStore
__author__ = 'itay.mizeretz' __author__ = 'itay.mizeretz'
def init_jwt(app): def init_jwt(app):
users = env.get_auth_users() UserStore.set_users(env.get_auth_users())
username_table = {u.username: u for u in users}
userid_table = {u.id: u for u in users}
def authenticate(username, secret): def authenticate(username, secret):
user = username_table.get(username, None) user = UserStore.username_table.get(username, None)
if user and safe_str_cmp(user.secret.encode('utf-8'), secret.encode('utf-8')): if user and safe_str_cmp(user.secret.encode('utf-8'), secret.encode('utf-8')):
return user return user
def identity(payload): def identity(payload):
user_id = payload['identity'] user_id = payload['identity']
return userid_table.get(user_id, None) return UserStore.userid_table.get(user_id, None)
JWT(app, authenticate, identity) JWT(app, authenticate, identity)

View File

@ -0,0 +1,15 @@
from typing import List
from monkey_island.cc.resources.auth.auth_user import User
class UserStore:
users = []
username_table = {}
userid_table = {}
@staticmethod
def set_users(users: List[User]):
UserStore.users = users
UserStore.username_table = {u.username: u for u in UserStore.users}
UserStore.userid_table = {u.id: u for u in UserStore.users}

View File

@ -3,7 +3,7 @@ import json
import flask_restful import flask_restful
from flask import request, jsonify, abort from flask import request, jsonify, abort
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.config import ConfigService

View File

@ -2,7 +2,7 @@ import logging
import flask_restful import flask_restful
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.island_logs import IslandLogService from monkey_island.cc.services.island_logs import IslandLogService
__author__ = "Maor.Rayzin" __author__ = "Maor.Rayzin"

View File

@ -4,7 +4,7 @@ import flask_restful
from bson import ObjectId from bson import ObjectId
from flask import request from flask import request
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.database import mongo from monkey_island.cc.database import mongo
from monkey_island.cc.resources.test.utils.telem_store import TestTelemStore from monkey_island.cc.resources.test.utils.telem_store import TestTelemStore
from monkey_island.cc.services.log import LogService from monkey_island.cc.services.log import LogService

View File

@ -3,7 +3,7 @@ import json
import flask_restful import flask_restful
from flask import request, jsonify, abort from flask import request, jsonify, abort
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.config import ConfigService
__author__ = 'Barak' __author__ = 'Barak'

View File

@ -1,6 +1,6 @@
import flask_restful import flask_restful
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.edge import EdgeService from monkey_island.cc.services.edge import EdgeService
from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.node import NodeService
from monkey_island.cc.database import mongo from monkey_island.cc.database import mongo

View File

@ -1,7 +1,7 @@
from flask import request from flask import request
import flask_restful import flask_restful
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.node import NodeService
__author__ = 'Barak' __author__ = 'Barak'

View File

@ -1,6 +1,6 @@
import flask_restful import flask_restful
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.utils.node_states import NodeStates as NodeStateList from monkey_island.cc.services.utils.node_states import NodeStates as NodeStateList

View File

@ -2,7 +2,7 @@ import flask_restful
from flask import request, send_from_directory, Response from flask import request, send_from_directory, Response
from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.config import ConfigService
from monkey_island.cc.services.post_breach_files import PBA_WINDOWS_FILENAME_PATH, PBA_LINUX_FILENAME_PATH, UPLOADS_DIR from monkey_island.cc.services.post_breach_files import PBA_WINDOWS_FILENAME_PATH, PBA_LINUX_FILENAME_PATH, UPLOADS_DIR
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
import os import os
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
import logging import logging

View File

@ -14,7 +14,7 @@ class Registration(flask_restful.Resource):
credentials = UserCreds.get_from_json(request.data) credentials = UserCreds.get_from_json(request.data)
try: try:
env.try_add_user(credentials) env.try_add_user(credentials)
return make_response({"error": ""}, 300) return make_response({"error": ""}, 200)
except InvalidRegistrationCredentials as e: except InvalidRegistrationCredentials as e:
return make_response({"error": e}, 400) return make_response({"error": str(e)}, 400)

View File

@ -4,7 +4,7 @@ from botocore.exceptions import NoCredentialsError, ClientError
from flask import request, jsonify, make_response from flask import request, jsonify, make_response
import flask_restful import flask_restful
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService
from common.cloud.aws.aws_service import AwsService from common.cloud.aws.aws_service import AwsService

View File

@ -3,7 +3,7 @@ import http.client
import flask_restful import flask_restful
from flask import jsonify from flask import jsonify
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.reporting.report import ReportService from monkey_island.cc.services.reporting.report import ReportService
from monkey_island.cc.services.reporting.zero_trust_service import ZeroTrustService from monkey_island.cc.services.reporting.zero_trust_service import ZeroTrustService

View File

@ -4,7 +4,7 @@ import threading
import flask_restful import flask_restful
from flask import request, make_response, jsonify from flask import request, make_response, jsonify
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.database import mongo from monkey_island.cc.database import mongo
from monkey_island.cc.services.database import Database from monkey_island.cc.services.database import Database
from monkey_island.cc.services.infection_lifecycle import InfectionLifecycle from monkey_island.cc.services.infection_lifecycle import InfectionLifecycle

View File

@ -6,7 +6,7 @@ import dateutil
import flask_restful import flask_restful
from flask import request from flask import request
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.database import mongo from monkey_island.cc.database import mongo
from monkey_island.cc.resources.test.utils.telem_store import TestTelemStore from monkey_island.cc.resources.test.utils.telem_store import TestTelemStore
from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.node import NodeService

View File

@ -6,7 +6,7 @@ import flask_restful
from flask import request from flask import request
import flask_pymongo import flask_pymongo
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.database import mongo from monkey_island.cc.database import mongo
from monkey_island.cc.services.node import NodeService from monkey_island.cc.services.node import NodeService

View File

@ -2,7 +2,7 @@ import logging
import flask_restful import flask_restful
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.attack.attack_report import AttackReportService from monkey_island.cc.services.attack.attack_report import AttackReportService
from monkey_island.cc.services.reporting.report import ReportService from monkey_island.cc.services.reporting.report import ReportService

View File

@ -2,7 +2,7 @@ from bson import json_util
import flask_restful import flask_restful
from flask import request from flask import request
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.database import mongo, database from monkey_island.cc.database import mongo, database

View File

@ -2,7 +2,7 @@ from bson import json_util
import flask_restful import flask_restful
from flask import request from flask import request
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.database import mongo from monkey_island.cc.database import mongo

View File

@ -1,7 +1,7 @@
import flask_restful import flask_restful
import json import json
from monkey_island.cc.auth import jwt_required from monkey_island.cc.resources.auth.auth import jwt_required
from monkey_island.cc.services.reporting.zero_trust_service import ZeroTrustService from monkey_island.cc.services.reporting.zero_trust_service import ZeroTrustService

View File

@ -15,6 +15,7 @@ import ReportPage from 'components/pages/ReportPage';
import LicensePage from 'components/pages/LicensePage'; import LicensePage from 'components/pages/LicensePage';
import AuthComponent from 'components/AuthComponent'; import AuthComponent from 'components/AuthComponent';
import LoginPageComponent from 'components/pages/LoginPage'; import LoginPageComponent from 'components/pages/LoginPage';
import RegisterPageComponent from 'components/pages/RegisterPage';
import Notifier from 'react-desktop-notification'; import Notifier from 'react-desktop-notification';
import NotFoundPage from 'components/pages/NotFoundPage'; import NotFoundPage from 'components/pages/NotFoundPage';
@ -43,6 +44,15 @@ class AppComponent extends AuthComponent {
}); });
} }
if (!res){
this.auth.needsRegistration()
.then(result => {
this.setState({
needsRegistration: result
});
})
}
if (res) { if (res) {
this.authFetch('/api') this.authFetch('/api')
.then(res => res.json()) .then(res => res.json())
@ -69,11 +79,17 @@ class AppComponent extends AuthComponent {
switch (this.state.isLoggedIn) { switch (this.state.isLoggedIn) {
case true: case true:
return page_component; return page_component;
case false:
switch (this.state.needsRegistration){
case true:
return <Redirect to={{pathname: '/register'}}/>
case false: case false:
return <Redirect to={{pathname: '/login'}}/>; return <Redirect to={{pathname: '/login'}}/>;
default: default:
return page_component; return page_component;
}
default:
return page_component;
} }
}; };
@ -100,7 +116,8 @@ class AppComponent extends AuthComponent {
run_monkey: false, run_monkey: false,
infection_done: false, infection_done: false,
report_done: false, report_done: false,
isLoggedIn: undefined isLoggedIn: undefined,
needsRegistration: undefined
} }
}; };
} }
@ -202,6 +219,7 @@ class AppComponent extends AuthComponent {
<Switch> <Switch>
<Route path='/login' render={() => (<LoginPageComponent onStatusChange={this.updateStatus}/>)}/> <Route path='/login' render={() => (<LoginPageComponent onStatusChange={this.updateStatus}/>)}/>
<Route path='/register' render={() => (<RegisterPageComponent onStatusChange={this.updateStatus}/>)}/>
{this.renderRoute('/', <RunServerPage onStatusChange={this.updateStatus}/>, true)} {this.renderRoute('/', <RunServerPage onStatusChange={this.updateStatus}/>, true)}
{this.renderRoute('/configure', <ConfigurePage onStatusChange={this.updateStatus}/>)} {this.renderRoute('/configure', <ConfigurePage onStatusChange={this.updateStatus}/>)}
{this.renderRoute('/run-monkey', <RunMonkeyPage onStatusChange={this.updateStatus}/>)} {this.renderRoute('/run-monkey', <RunMonkeyPage onStatusChange={this.updateStatus}/>)}

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import {Col} from 'react-bootstrap'; import {Col} from 'react-bootstrap';
import AuthService from '../../services/AuthService' import AuthService from '../../services/AuthService';
class LoginPageComponent extends React.Component { class LoginPageComponent extends React.Component {
login = () => { login = () => {
@ -26,6 +26,10 @@ class LoginPageComponent extends React.Component {
window.location.href = '/'; window.location.href = '/';
}; };
redirectToRegistration = () => {
window.location.href = '/register';
};
constructor(props) { constructor(props) {
super(props); super(props);
this.username = ''; this.username = '';
@ -34,6 +38,13 @@ class LoginPageComponent extends React.Component {
this.state = { this.state = {
failed: false failed: false
}; };
this.auth.needsRegistration()
.then(result => {
if(result){
this.redirectToRegistration()
}
})
this.auth.loggedIn() this.auth.loggedIn()
.then(res => { .then(res => {
if (res) { if (res) {

View File

@ -0,0 +1,85 @@
import React from 'react';
import {Col} from 'react-bootstrap';
import AuthService from '../../services/AuthService';
class RegisterPageComponent extends React.Component {
register = () => {
this.auth.register(this.username, this.password).then(res => {
this.setState({failed: false, error: ""});
if (res['result']) {
this.redirectToHome();
} else {
this.setState({failed: true,
error: res['error']});
}
});
};
updateUsername = (evt) => {
this.username = evt.target.value;
};
updatePassword = (evt) => {
this.password = evt.target.value;
};
redirectToHome = () => {
window.location.href = '/';
};
constructor(props) {
super(props);
this.username = '';
this.password = '';
this.auth = new AuthService();
this.state = {
failed: false,
loading: false
};
this.auth.needsRegistration()
.then(result => {
if(!result){
this.redirectToHome()
}
})
}
render() {
return (
<Col xs={12} lg={8}>
<h1 className="page-title">First time?</h1>
<h3 className="page-title">Let's secure your island</h3>
<div className="col-sm-6 col-sm-offset-3" style={{'fontSize': '1.2em'}}>
<div className="panel panel-default">
<div className="panel-heading text-center">
<b>Register</b>
</div>
<div className="panel-body">
<div className="input-group center-block text-center">
<input type="text" className="form-control" placeholder="Username"
onChange={evt => this.updateUsername(evt)}/>
<input type="password" className="form-control" placeholder="Password"
onChange={evt => this.updatePassword(evt)}/>
<button type="button" className="btn btn-primary btn-lg" style={{margin: '5px'}}
onClick={() => {
this.register()
}}>
Lets Go!
</button>
{
this.state.failed ?
<div className="alert alert-danger" role="alert">{this.state.error}</div>
:
''
}
</div>
</div>
</div>
</div>
</Col>
);
}
}
export default RegisterPageComponent;

View File

@ -8,6 +8,8 @@ export default class AuthService {
'8d2c8d0b1538d2208c1444ac66535b764a3d902b35e751df3faec1e477ed3557'; '8d2c8d0b1538d2208c1444ac66535b764a3d902b35e751df3faec1e477ed3557';
SECONDS_BEFORE_JWT_EXPIRES = 20; SECONDS_BEFORE_JWT_EXPIRES = 20;
AUTHENTICATION_API_ENDPOINT = '/api/auth';
REGISTRATION_API_ENDPOINT = '/api/registration';
login = (username, password) => { login = (username, password) => {
return this._login(username, this.hashSha3(password)); return this._login(username, this.hashSha3(password));
@ -30,7 +32,7 @@ export default class AuthService {
} }
_login = (username, password) => { _login = (username, password) => {
return this._authFetch('/api/auth', { return this._authFetch(this.AUTHENTICATION_API_ENDPOINT, {
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
username, username,
@ -48,6 +50,28 @@ export default class AuthService {
}) })
}; };
register = (username, password) => {
return this._register(username, this.hashSha3(password));
};
_register = (username, password) => {
return this._authFetch(this.REGISTRATION_API_ENDPOINT, {
method: 'POST',
body: JSON.stringify({
'user': username,
'password_hash': password
})
}).then(res => {
if (res.status === 200) {
return this._login(username, password)
} else {
return res.json().then(res_json => {
return {result: false, error: res_json['error']};
})
}
})
};
_authFetch = (url, options = {}) => { _authFetch = (url, options = {}) => {
const headers = { const headers = {
'Accept': 'application/json', 'Accept': 'application/json',
@ -72,7 +96,16 @@ export default class AuthService {
this._removeToken(); this._removeToken();
} }
return res; return res;
}); })
};
needsRegistration = () => {
return fetch(this.REGISTRATION_API_ENDPOINT,
{method: 'GET'})
.then(response => response.json())
.then(res => {
return res['needs_registration']
})
}; };
async loggedIn() { async loggedIn() {