summaryrefslogtreecommitdiff
path: root/settings/accounts/ui/fediverse-update.qml
diff options
context:
space:
mode:
Diffstat (limited to 'settings/accounts/ui/fediverse-update.qml')
-rw-r--r--settings/accounts/ui/fediverse-update.qml229
1 files changed, 229 insertions, 0 deletions
diff --git a/settings/accounts/ui/fediverse-update.qml b/settings/accounts/ui/fediverse-update.qml
new file mode 100644
index 0000000..fe75089
--- /dev/null
+++ b/settings/accounts/ui/fediverse-update.qml
@@ -0,0 +1,229 @@
+/*
+ * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import QtQuick 2.0
+import Sailfish.Silica 1.0
+import Sailfish.Accounts 1.0
+import com.jolla.settings.accounts 1.0
+import com.jolla.settings.accounts.fediverse 1.0
+
+AccountCredentialsAgent {
+ id: root
+
+ property bool _started
+
+ readonly property string callbackUri: "http://ipv4.jolla.com/online/status.html"
+ readonly property string defaultServerHost: "mastodon.social"
+
+ function normalizeApiHost(rawHost) {
+ var host = rawHost ? rawHost.trim() : ""
+ if (host.length === 0) {
+ host = defaultServerHost
+ }
+
+ host = host.replace(/^https?:\/\//i, "")
+ var pathSeparator = host.indexOf("/")
+ if (pathSeparator !== -1) {
+ host = host.substring(0, pathSeparator)
+ }
+ host = host.replace(/\/+$/, "")
+
+ if (host.length === 0) {
+ host = defaultServerHost
+ }
+ return "https://" + host.toLowerCase()
+ }
+
+ function _valueFromServiceConfig(config, key) {
+ return config && config[key] ? config[key].toString() : ""
+ }
+
+ function _extractAccountName(responseData) {
+ if (!responseData) {
+ return ""
+ }
+
+ var candidates = [
+ "AccountUsername",
+ "UserName",
+ "user_name",
+ "acct",
+ "username",
+ "preferred_username",
+ "login",
+ "ScreenName"
+ ]
+ for (var i = 0; i < candidates.length; ++i) {
+ var value = responseData[candidates[i]]
+ if (value) {
+ var userName = value.toString().trim()
+ if (userName.length > 0) {
+ return userName
+ }
+ }
+ }
+
+ return ""
+ }
+
+ function _formatFediverseAccountId(accountName, apiHost) {
+ var value = accountName ? accountName.toString().trim() : ""
+ if (value.length === 0) {
+ return ""
+ }
+
+ value = value.replace(/^@+/, "")
+ if (value.indexOf("@") !== -1) {
+ return "@" + value
+ }
+
+ var host = apiHost.replace(/^https?:\/\//i, "")
+ if (host.length === 0) {
+ return ""
+ }
+
+ return "@" + value + "@" + host
+ }
+
+ function _extractAccessToken(responseData) {
+ if (!responseData) {
+ return ""
+ }
+
+ var token = responseData["AccessToken"]
+ if (!token || token.toString().trim().length === 0) {
+ token = responseData["access_token"]
+ }
+ return token ? token.toString().trim() : ""
+ }
+
+ function _isFediverseAccountId(value) {
+ var text = value ? value.toString().trim() : ""
+ return /^@[^@]+@[^@]+$/.test(text)
+ }
+
+ function _completeUpdate() {
+ root.credentialsUpdated(root.accountId)
+ root.goToEndDestination()
+ }
+
+ function _saveDescription(description) {
+ if (description.length > 0) {
+ account.setConfigurationValue("", "description", description)
+ if (_isFediverseAccountId(description)) {
+ account.setConfigurationValue("", "default_credentials_username", description)
+ }
+ }
+ account.sync()
+ _completeUpdate()
+ }
+
+ function _updateDescription(responseData) {
+ var config = account.configurationValues("fediverse-microblog")
+ var apiHost = normalizeApiHost(_valueFromServiceConfig(config, "api/Host"))
+ var description = _formatFediverseAccountId(_extractAccountName(responseData), apiHost)
+ if (description.length > 0) {
+ _saveDescription(description)
+ return
+ }
+
+ var accessToken = _extractAccessToken(responseData)
+ if (accessToken.length === 0) {
+ _completeUpdate()
+ return
+ }
+
+ var xhr = new XMLHttpRequest()
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState !== XMLHttpRequest.DONE) {
+ return
+ }
+
+ var fetchedDescription = ""
+ if (xhr.status >= 200 && xhr.status < 300) {
+ try {
+ var response = JSON.parse(xhr.responseText)
+ fetchedDescription = _formatFediverseAccountId(_extractAccountName(response), apiHost)
+ } catch (err) {
+ }
+ }
+
+ if (fetchedDescription.length > 0) {
+ _saveDescription(fetchedDescription)
+ } else {
+ _completeUpdate()
+ }
+ }
+
+ xhr.open("GET", apiHost + "/api/v1/accounts/verify_credentials")
+ xhr.setRequestHeader("Authorization", "Bearer " + accessToken)
+ xhr.send()
+ }
+
+ function _startUpdate() {
+ if (_started || initialPage.status !== PageStatus.Active || account.status !== Account.Initialized) {
+ return
+ }
+
+ var config = account.configurationValues("fediverse-microblog")
+ var apiHost = normalizeApiHost(_valueFromServiceConfig(config, "api/Host"))
+ var oauthHost = _valueFromServiceConfig(config, "auth/oauth2/web_server/Host")
+ if (oauthHost.length === 0) {
+ oauthHost = apiHost.replace(/^https?:\/\//i, "")
+ }
+
+ var clientId = _valueFromServiceConfig(config, "auth/oauth2/web_server/ClientId")
+ var clientSecret = _valueFromServiceConfig(config, "auth/oauth2/web_server/ClientSecret")
+ if (clientId.length === 0 || clientSecret.length === 0) {
+ //% "Missing Fediverse OAuth client credentials"
+ credentialsUpdateError(qsTrId("settings-accounts-fediverse-la-missing_client_credentials"))
+ return
+ }
+
+ _started = true
+
+ var sessionData = {
+ "ClientId": clientId,
+ "ClientSecret": clientSecret,
+ "Host": oauthHost,
+ "AuthPath": "oauth/authorize",
+ "TokenPath": "oauth/token",
+ "ResponseType": "code",
+ "Scope": ["read", "write"],
+ "RedirectUri": callbackUri
+ }
+ initialPage.prepareAccountCredentialsUpdate(account, root.accountProvider, "fediverse-microblog", sessionData)
+ }
+
+ Account {
+ id: account
+ identifier: root.accountId
+
+ onStatusChanged: {
+ root._startUpdate()
+ }
+ }
+
+ initialPage: OAuthAccountSetupPage {
+ onStatusChanged: {
+ root._startUpdate()
+ }
+
+ onAccountCredentialsUpdated: {
+ root._updateDescription(responseData)
+ }
+
+ onAccountCredentialsUpdateError: {
+ root.credentialsUpdateError(errorMessage)
+ }
+
+ onPageContainerChanged: {
+ if (pageContainer == null) {
+ cancelSignIn()
+ }
+ }
+ }
+}