diff --git a/components/app.js b/components/app.js index 094a5f5..856206f 100644 --- a/components/app.js +++ b/components/app.js @@ -8,12 +8,13 @@ import ConnectForm from "./connect-form.js"; import JoinForm from "./join-form.js"; import Help from "./help.js"; import NetworkForm from "./network-form.js"; +import AuthForm from "./auth-form.js"; import Composer from "./composer.js"; import ScrollManager from "./scroll-manager.js"; import Dialog from "./dialog.js"; import { html, Component, createRef } from "../lib/index.js"; import { strip as stripANSI } from "../lib/ansi.js"; -import { SERVER_BUFFER, BufferType, ReceiptType, ServerStatus, Unread, State } from "../state.js"; +import { SERVER_BUFFER, BufferType, ReceiptType, ServerStatus, Unread, State, getServerName } from "../state.js"; import commands from "../commands.js"; import { setup as setupKeybindings } from "../keybindings.js"; import * as store from "../store.js"; @@ -191,6 +192,7 @@ export default class App extends Component { this.handleNetworkSubmit = this.handleNetworkSubmit.bind(this); this.handleNetworkRemove = this.handleNetworkRemove.bind(this); this.handleDismissError = this.handleDismissError.bind(this); + this.handleAuthSubmit = this.handleAuthSubmit.bind(this); this.saveReceipts = debounce(this.saveReceipts.bind(this), 500); @@ -1377,6 +1379,35 @@ export default class App extends Component { this.setState({ dialog: null, dialogData: null }); } + handleAuthClick(serverID) { + let client = this.clients.get(serverID); + this.openDialog("auth", { username: client.nick }); + } + + handleAuthSubmit(username, password) { + let serverID = State.getActiveServerID(this.state); + let client = this.clients.get(serverID); + client.authenticate("PLAIN", { username, password }).then(() => { + let firstClient = this.clients.values().next().value; + if (client !== firstClient) { + return; + } + + let autoconnect = store.autoconnect.load(); + if (!autoconnect) { + return; + } + + console.log("Saving SASL PLAIN credentials"); + autoconnect = { + ...autoconnect, + saslPlain: { username, password }, + }; + store.autoconnect.put(autoconnect); + }); + this.dismissDialog(); + } + handleAddNetworkClick() { this.openDialog("network"); } @@ -1560,6 +1591,13 @@ export default class App extends Component { > `; break; + case "auth": + dialog = html` + <${Dialog} title="Login to ${getServerName(activeServer, activeBouncerNetwork, isBouncer)}" onDismiss=${this.dismissDialog}> + <${AuthForm} username=${dialogData.username} onSubmit=${this.handleAuthSubmit}/> + > + `; + break; } let error = null; @@ -1616,7 +1654,9 @@ export default class App extends Component { server=${activeServer} isBouncer=${isBouncer} onChannelClick=${this.handleChannelClick} - onNickClick=${this.handleNickClick}/> + onNickClick=${this.handleNickClick} + onAuthClick=${() => this.handleAuthClick(activeBuffer.server)} + /> > ${memberList} diff --git a/components/auth-form.js b/components/auth-form.js new file mode 100644 index 0000000..6eccdaa --- /dev/null +++ b/components/auth-form.js @@ -0,0 +1,51 @@ +import { html, Component } from "../lib/index.js"; + +export default class NetworkForm extends Component { + state = { + username: "", + password: "", + }; + + constructor(props) { + super(props); + + this.handleChange = this.handleChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + + if (props.username) { + this.state.username = props.username; + } + } + + handleChange(event) { + let target = event.target; + let value = target.type == "checkbox" ? target.checked : target.value; + this.setState({ [target.name]: value }); + } + + handleSubmit(event) { + event.preventDefault(); + + this.props.onSubmit(this.state.username, this.state.password); + } + + render() { + return html` +
+ `; + } +} diff --git a/components/buffer.js b/components/buffer.js index e661a1b..8f2e30e 100644 --- a/components/buffer.js +++ b/components/buffer.js @@ -2,7 +2,7 @@ import { html, Component } from "../lib/index.js"; import linkify from "../lib/linkify.js"; import * as irc from "../lib/irc.js"; import { strip as stripANSI } from "../lib/ansi.js"; -import { BufferType, getNickURL, getChannelURL, getMessageURL } from "../state.js"; +import { BufferType, ServerStatus, getNickURL, getChannelURL, getMessageURL } from "../state.js"; import * as store from "../store.js"; import Membership from "./membership.js"; @@ -457,6 +457,26 @@ class ProtocolHandlerNagger extends Component { } } +function AuthNagger({ server, onClick }) { + let accDesc = "an account on this server"; + if (server.isupport.has("NETWORK")) { + accDesc = "a " + server.isupport.get("NETWORK") + " account"; + } + + function handleClick(event) { + event.preventDefault(); + onClick(); + } + + return html` +