Implement logging out from the bridge
But there is no API for logging out of KakaoTalk
This commit is contained in:
parent
db41292be7
commit
bb3d7057b3
|
@ -24,7 +24,7 @@ from mautrix.util.signed_token import sign_token
|
|||
from ..kt.client import Client as KakaoTalkClient
|
||||
from ..kt.client.errors import DeviceVerificationRequired, IncorrectPasscode, IncorrectPassword, CommandException
|
||||
|
||||
#from .. import puppet as pu
|
||||
from .. import puppet as pu
|
||||
from .typehint import CommandEvent
|
||||
|
||||
SECTION_AUTH = HelpSection("Authentication", 10, "")
|
||||
|
@ -53,7 +53,7 @@ try_again_or_cancel = "Try again, or say `$cmdprefix+sp cancel` to give up."
|
|||
help_args="[_email_]",
|
||||
)
|
||||
async def login(evt: CommandEvent) -> None:
|
||||
if evt.sender.client:
|
||||
if await evt.sender.is_logged_in():
|
||||
await evt.reply("You're already logged in")
|
||||
return
|
||||
|
||||
|
@ -156,10 +156,43 @@ async def _handle_login_failure(evt: CommandEvent, e: Exception) -> None:
|
|||
await evt.reply(f"{message}: {e}")
|
||||
|
||||
|
||||
@command_handler(needs_auth=True, help_section=SECTION_AUTH, help_text="Log out of KakaoTalk")
|
||||
@command_handler(
|
||||
needs_auth=True,
|
||||
help_section=SECTION_AUTH,
|
||||
help_text="Log out of KakaoTalk (and optionally change your virtual device ID for next login)",
|
||||
help_args="[--reset-device]",
|
||||
)
|
||||
async def logout(evt: CommandEvent) -> None:
|
||||
#puppet = await pu.Puppet.get_by_ktid(evt.sender.ktid)
|
||||
await evt.sender.logout()
|
||||
#if puppet.is_real_user:
|
||||
# await puppet.switch_mxid(None, None)
|
||||
await evt.reply("Successfully logged out")
|
||||
if len(evt.args) >= 1:
|
||||
if evt.args[0] == "--reset-device":
|
||||
reset_device = True
|
||||
else:
|
||||
await evt.reply("**Usage:** `$cmdprefix+sp logout [--reset-device]`")
|
||||
return
|
||||
else:
|
||||
reset_device = False
|
||||
|
||||
puppet = await pu.Puppet.get_by_ktid(evt.sender.ktid)
|
||||
await evt.sender.logout(reset_device=reset_device)
|
||||
if puppet.is_real_user:
|
||||
await puppet.switch_mxid(None, None)
|
||||
|
||||
message = "Successfully logged out"
|
||||
if reset_device:
|
||||
message += (
|
||||
", and your next login will use a different device ID.\n\n"
|
||||
"The old device must be manually de-registered from the KakaoTalk app."
|
||||
)
|
||||
await evt.reply(message)
|
||||
|
||||
|
||||
@command_handler(needs_auth=False, help_section=SECTION_AUTH, help_text="Change your virtual device ID for next login")
|
||||
async def reset_device(evt: CommandEvent) -> None:
|
||||
if await evt.sender.is_logged_in():
|
||||
await evt.reply("This command requires you to be logged out.")
|
||||
else:
|
||||
await evt.sender.logout(reset_device=True)
|
||||
await evt.reply(
|
||||
"Your next login will use a different device ID.\n\n"
|
||||
"The old device must be manually de-registered from the KakaoTalk app."
|
||||
)
|
||||
|
|
|
@ -172,7 +172,7 @@ class User(DBUser, BaseUser):
|
|||
|
||||
@property
|
||||
def has_state(self) -> bool:
|
||||
return self.uuid and self.ktid and self.access_token and self.refresh_token
|
||||
return bool(self.uuid and self.ktid and self.access_token and self.refresh_token)
|
||||
|
||||
# region Database getters
|
||||
|
||||
|
@ -233,10 +233,13 @@ class User(DBUser, BaseUser):
|
|||
|
||||
async def get_uuid(self, force: bool = False) -> str:
|
||||
if self.uuid is None or force:
|
||||
self.uuid = await Client.generate_uuid(await self.get_all_uuids())
|
||||
self.uuid = await self._generate_uuid()
|
||||
await self.save()
|
||||
return self.uuid
|
||||
|
||||
async def _generate_uuid(self) -> str:
|
||||
return await Client.generate_uuid(await self.get_all_uuids())
|
||||
|
||||
# endregion
|
||||
|
||||
@property
|
||||
|
@ -369,8 +372,7 @@ class User(DBUser, BaseUser):
|
|||
finally:
|
||||
self._is_refreshing = False
|
||||
|
||||
async def logout(self, remove_ktid: bool = True) -> bool:
|
||||
# TODO Remove tokens too?
|
||||
async def logout(self, *, remove_ktid: bool = True, reset_device: bool = False) -> bool:
|
||||
ok = True
|
||||
self.stop_listen()
|
||||
if self.has_state:
|
||||
|
@ -385,12 +387,15 @@ class User(DBUser, BaseUser):
|
|||
await self.client.stop()
|
||||
self.client = None
|
||||
|
||||
if remove_ktid:
|
||||
if self.ktid:
|
||||
#await UserPortal.delete_all(self.ktid)
|
||||
del self.by_ktid[self.ktid]
|
||||
self.ktid = None
|
||||
self.uuid = None
|
||||
if self.ktid and remove_ktid:
|
||||
#await UserPortal.delete_all(self.ktid)
|
||||
del self.by_ktid[self.ktid]
|
||||
self.ktid = None
|
||||
|
||||
if reset_device:
|
||||
self.uuid = await self._generate_uuid()
|
||||
self.access_token = None
|
||||
self.refresh_token = None
|
||||
|
||||
await self.save()
|
||||
return ok
|
||||
|
@ -583,7 +588,7 @@ class User(DBUser, BaseUser):
|
|||
self.log.info("TODO: stop_listen")
|
||||
|
||||
async def on_logged_in(self, oauth_credential: OAuthCredential) -> None:
|
||||
self.log.debug(f"Successfully logged in as {oauth_credential.uuid}")
|
||||
self.log.debug(f"Successfully logged in as {oauth_credential.userId}")
|
||||
self.oauth_credential = oauth_credential
|
||||
self.client = Client(self, log=self.log.getChild("ktclient"))
|
||||
await self.save()
|
||||
|
|
|
@ -28,6 +28,7 @@ import {
|
|||
|
||||
|
||||
class UserClient {
|
||||
static #initializing = false
|
||||
|
||||
#talkClient = new TalkClient()
|
||||
get talkClient() { return this.#talkClient }
|
||||
|
@ -37,16 +38,28 @@ class UserClient {
|
|||
get serviceClient() { return this.#serviceClient }
|
||||
|
||||
/**
|
||||
* @param {string} mxid The ID of the associated Matrix user
|
||||
* @param {OAuthCredential} credential The tokens that API calls may use
|
||||
* DO NOT CONSTRUCT DIRECTLY. Callers should use {@link UserClient#create} instead.
|
||||
* @param {string} mxid
|
||||
* @param {OAuthCredential} credential
|
||||
*/
|
||||
constructor(mxid, credential) {
|
||||
if (!UserClient.#initializing) {
|
||||
throw new Error("Private constructor")
|
||||
}
|
||||
UserClient.#initializing = false
|
||||
|
||||
this.mxid = mxid
|
||||
this.credential = credential
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} mxid The ID of the associated Matrix user
|
||||
* @param {OAuthCredential} credential The tokens that API calls may use
|
||||
*/
|
||||
static async create(mxid, credential) {
|
||||
this.#initializing = true
|
||||
const userClient = new UserClient(mxid, credential)
|
||||
|
||||
userClient.#serviceClient = await ServiceApiClient.create(this.credential)
|
||||
return userClient
|
||||
}
|
||||
|
@ -194,9 +207,9 @@ export default class PeerClient {
|
|||
/**
|
||||
* Checked lookup of a UserClient for a given mxid.
|
||||
* @param {string} mxid
|
||||
* @returns {UserClient}
|
||||
*/
|
||||
#getUser(mxid) {
|
||||
/** @type {UserClient} */
|
||||
const userClient = this.userClients.get(mxid)
|
||||
if (userClient === undefined) {
|
||||
throw new Error(`Could not find user ${mxid}`)
|
||||
|
@ -204,6 +217,17 @@ export default class PeerClient {
|
|||
return userClient
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service client for the specified user ID, or create
|
||||
* and return a new service client if no user ID is provided.
|
||||
* @param {string} mxid
|
||||
* @param {OAuthCredential} oauth_credential
|
||||
*/
|
||||
async #getServiceClient(mxid, oauth_credential) {
|
||||
return this.userClients.get(mxid)?.serviceClient ||
|
||||
await ServiceApiClient.create(oauth_credential)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} req
|
||||
* @param {OAuthCredential} req.oauth_credential
|
||||
|
@ -270,9 +294,7 @@ export default class PeerClient {
|
|||
* @param {OAuthCredential} req.oauth_credential
|
||||
*/
|
||||
getOwnProfile = async (req) => {
|
||||
const serviceClient =
|
||||
this.userClients.get(req.mxid)?.serviceClient ||
|
||||
await ServiceApiClient.create(req.oauth_credential)
|
||||
const serviceClient = await this.#getServiceClient(req.mxid, req.oauth_credential)
|
||||
return await serviceClient.requestMyProfile()
|
||||
}
|
||||
|
||||
|
@ -283,10 +305,8 @@ export default class PeerClient {
|
|||
* @param {Long} req.user_id
|
||||
*/
|
||||
getProfile = async (req) => {
|
||||
const serviceClient =
|
||||
this.userClients.get(mxid)?.serviceClient ||
|
||||
await ServiceApiClient.create(req.oauth_credential)
|
||||
return await serviceClient.requestProfile(user_id)
|
||||
const serviceClient = await this.#getServiceClient(req.mxid, req.oauth_credential)
|
||||
return await serviceClient.requestProfile(req.user_id)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -310,6 +330,16 @@ export default class PeerClient {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} req
|
||||
* @param {string} req.mxid
|
||||
*/
|
||||
handleStop = async (req) => {
|
||||
this.#getUser(req.mxid).close()
|
||||
this.userClients.delete(req.mxid)
|
||||
return this.#voidCommandResult
|
||||
}
|
||||
|
||||
#makeCommandResult(result) {
|
||||
return {
|
||||
success: true,
|
||||
|
@ -318,12 +348,9 @@ export default class PeerClient {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} req
|
||||
* @param {string} req.mxid
|
||||
*/
|
||||
handleStop = async (req) => {
|
||||
this.#getUser(req.mxid).close()
|
||||
#voidCommandResult = {
|
||||
success: true,
|
||||
status: 0,
|
||||
}
|
||||
|
||||
handleUnknownCommand = () => {
|
||||
|
|
Loading…
Reference in New Issue