// matrix-appservice-kakaotalk - A Matrix-KakaoTalk puppeting bridge.
// Copyright (C) 2021 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
import { h, Component, render } from "../lib/preact-10.5.12.min.js"
import htm from "../lib/htm-3.0.4.min.js"
import * as api from "./api.js"
const html = htm.bind(h)
class App extends Component {
constructor(props) {
super(props)
this.approveCheckInterval = null
this.state = {
loading: true,
submitting: false,
error: null,
mxid: null,
facebook: null,
status: "pre-login",
pubkey: null,
keyID: null,
email: "",
password: "",
twoFactorCode: "",
twoFactorInfo: {},
}
}
async componentDidMount() {
const { error, mxid, facebook } = await api.whoami()
if (error) {
this.setState({ error, loading: false })
} else {
this.setState({ mxid, facebook, loading: false })
}
}
checkLoginApproved = async () => {
if (!await api.wasLoginApproved()) {
return
}
clearInterval(this.approveCheckInterval)
this.approveCheckInterval = null
const resp = await api.loginApproved()
if (resp.status === "logged-in") {
this.setState({ status: resp.status })
}
}
submitNoDefault = evt => {
evt.preventDefault()
this.submit()
}
async submit() {
if (this.approveCheckInterval) {
clearInterval(this.approveCheckInterval)
this.approveCheckInterval = null
}
this.setState({ submitting: true })
let resp
switch (this.state.status) {
case "pre-login":
resp = await api.prepareLogin()
break
case "login":
resp = await api.login(this.state.pubkey, this.state.keyID,
this.state.email, this.state.password)
break
case "two-factor":
resp = await api.login2FA(this.state.email, this.state.twoFactorCode)
break
}
const stateUpdate = { submitting: false }
if (typeof resp.error === "string") {
stateUpdate.error = resp.error
} else {
stateUpdate.status = resp.status
}
if (resp.password_encryption_key_id) {
stateUpdate.pubkey = resp.password_encryption_pubkey
stateUpdate.keyID = resp.password_encryption_key_id
}
if (resp.status === "two-factor") {
this.approveCheckInterval = setInterval(this.checkLoginApproved, 5000)
stateUpdate.twoFactorInfo = resp.error
} else if (resp.status === "logged-in") {
api.whoami().then(({ facebook }) => this.setState({ facebook }))
}
this.setState(stateUpdate)
}
fieldChange = evt => {
this.setState({ [evt.target.id]: evt.target.value })
}
renderFields() {
switch (this.state.status) {
case "pre-login":
return null
case "login":
return html`
`
case "two-factor":
return html`
${this.state.twoFactorInfo.error_user_msg}
`
}
}
submitButtonText() {
switch (this.state.status) {
case "pre-login":
return "Start"
case "login":
case "two-factor":
return "Sign in"
}
}
renderContent() {
if (this.state.loading) {
return html`
Loading...
`
} else if (this.state.status === "logged-in") {
if (this.state.facebook) {
return html`
Successfully logged in as ${this.state.facebook.name}. The bridge will appear
as ${this.state.facebook.device_displayname} in Facebook security settings.
`
}
return html`
Successfully logged in
`
} else if (this.state.facebook) {
return html`
You're already logged in as ${this.state.facebook.name}. The bridge appears
as ${this.state.facebook.device_displayname} in Facebook security settings.
`
}
return html`
${this.state.error && html`