Skip to content

Commit

Permalink
Allow to change web UI username and password (fixes #1018) (#1019)
Browse files Browse the repository at this point in the history
* Update adb_pull_config_xml.cmd

* Update strings.xml

* Update app_settings.xml

* Update SettingsActivity.java

* Update Gui.java

* Update Gui.java

* Create adb_delete_config_xml.cmd

* Update adb_delete_config_xml.cmd

* Update ConfigXml.java

* Update ConfigXml.java

* const

* Update ConfigXml.java

* Update SettingsActivity.java

* gui auth

* Revert "Update adb_pull_config_xml.cmd"
  • Loading branch information
Catfriend1 authored Oct 21, 2023
1 parent 0de3360 commit c0fe2ee
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
import com.nutomic.syncthingandroid.util.Util;
import com.nutomic.syncthingandroid.views.WifiSsidPreference;

import org.mindrot.jbcrypt.BCrypt;

import java.io.File;
import java.lang.ref.WeakReference;
import java.security.InvalidParameterException;
Expand Down Expand Up @@ -191,6 +193,8 @@ public static class SettingsFragment extends PreferenceFragment
private CheckBoxPreference mRelaysEnabled;
private EditTextPreference mGlobalAnnounceServers;
private EditTextPreference mWebUITcpPort;
private EditTextPreference mWebUIUsername;
private EditTextPreference mWebUIPassword;
private CheckBoxPreference mWebUIRemoteAccess;
private CheckBoxPreference mUrAccepted;
private CheckBoxPreference mCrashReportingEnabled;
Expand Down Expand Up @@ -330,6 +334,8 @@ public void onActivityCreated(Bundle savedInstanceState) {
mRelaysEnabled = (CheckBoxPreference) findPreference("relaysEnabled");
mGlobalAnnounceServers = (EditTextPreference) findPreference("globalAnnounceServers");
mWebUITcpPort = (EditTextPreference) findPreference(KEY_WEBUI_TCP_PORT);
mWebUIUsername = (EditTextPreference) findPreference(Constants.PREF_WEBUI_USERNAME);
mWebUIPassword = (EditTextPreference) findPreference(Constants.PREF_WEBUI_PASSWORD);
mWebUIRemoteAccess = (CheckBoxPreference) findPreference(KEY_WEBUI_REMOTE_ACCESS);
mSyncthingApiKey = findPreference(KEY_SYNCTHING_API_KEY);
mUrAccepted = (CheckBoxPreference) findPreference("urAccepted");
Expand Down Expand Up @@ -542,6 +548,10 @@ public void onServiceStateChange(SyncthingService.State currentState) {
if (mGui != null) {
mWebUITcpPort.setText(mGui.getBindPort());
mWebUITcpPort.setSummary(mGui.getBindPort());

mWebUIUsername.setText(mGui.user);
mWebUIUsername.setSummary(mGui.user);

mWebUIRemoteAccess.setChecked(!BIND_LOCALHOST.equals(mGui.getBindAddress()));
mWebUIDebugging.setChecked(mGui.debugging);
mDownloadSupportBundle.setEnabled(mGui.debugging);
Expand Down Expand Up @@ -694,6 +704,13 @@ public boolean onSyncthingPreferenceChange(Preference preference, Object o) {
mWebUITcpPort.setSummary(Integer.toString(webUITcpPort));
mGui.address = mGui.getBindAddress() + ":" + Integer.toString(webUITcpPort);
break;
case Constants.PREF_WEBUI_USERNAME:
mWebUIUsername.setSummary((String) o);
mGui.user = (String) o;
break;
case Constants.PREF_WEBUI_PASSWORD:
mGui.password = BCrypt.hashpw((String) o, BCrypt.gensalt(4));
break;
case KEY_WEBUI_REMOTE_ACCESS:
mGui.address = ((boolean) o ? BIND_ALL : BIND_LOCALHOST) + ":" + mWebUITcpPort.getSummary();
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public void onServiceStateChange(SyncthingService.State newState) {
if (mWebView.getUrl() == null) {
mWebView.stopLoading();
setWebViewProxy(mWebView.getContext().getApplicationContext(), "", 0, "localhost|0.0.0.0|127.*|[::1]");
String credentials = mConfig.getUserName() + ":" + mConfig.getApiKey();
String credentials = mConfig.getWebUIUsername() + ":" + mConfig.getWebUIPassword();
String b64Credentials = Base64.encodeToString(credentials.getBytes(UTF_8), Base64.NO_WRAP);
Map<String,String> headers = new HashMap<>();
headers.put("Authorization", "Basic " + b64Credentials);
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/com/nutomic/syncthingandroid/model/Gui.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public class Gui {
public boolean useTLS = false;

public String address = "127.0.0.1:8384";
public String user = "syncthing"; // Default in this app
public String password; // This will be set to the "apiKey" in {@link ConfigXml#}
public String user;
public String password;
public String apiKey; // Automatically generated by SyncthingNative

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ private PowerSource() { }
public static final String PREF_USE_ROOT = "use_root";
public static final String PREF_BIND_NETWORK = "bind_network";

// Preferences - Syncthing Options
public static final String PREF_WEBUI_USERNAME = "webui_username";
public static final String PREF_WEBUI_PASSWORD = "webui_password";

// Preferences - Import and Export
public static final String PREF_BACKUP_FOLDER_NAME = "backup_folder_name";

Expand Down
50 changes: 23 additions & 27 deletions app/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,21 @@ public void generateConfig() throws OpenConfigException, SyncthingRunnable.Execu
// Set default folder to the "camera" folder: path and name
changed = changeDefaultFolder() || changed;

/* Section - GUI */
Element gui = getGuiElement();
if (gui == null) {
throw new OpenConfigException();
}

// Set user to "syncthing"
changed = setConfigElement(gui, "user", "syncthing") || changed;

// Initialiaze password to the API key
changed = setConfigElement(gui, "password", BCrypt.hashpw(getApiKey(), BCrypt.gensalt(4))) || changed;
PreferenceManager.getDefaultSharedPreferences(mContext).edit()
.putString(Constants.PREF_WEBUI_PASSWORD, getApiKey())
.apply();

// Save changes if we made any.
if (changed) {
saveChanges();
Expand Down Expand Up @@ -242,10 +257,14 @@ public String getApiKey() {
return getGuiElement().getElementsByTagName("apikey").item(0).getTextContent();
}

public String getUserName() {
public String getWebUIUsername() {
return getGuiElement().getElementsByTagName("user").item(0).getTextContent();
}

public String getWebUIPassword() {
return PreferenceManager.getDefaultSharedPreferences(mContext).getString(Constants.PREF_WEBUI_PASSWORD, "");
}

/**
* Updates the config file.
* Sets ignorePerms flag to true on every folder, force enables TLS, sets the
Expand Down Expand Up @@ -291,30 +310,6 @@ private void updateIfNeeded() {
changed = true;
}

// Set user to "syncthing"
changed = setConfigElement(gui, "user", "syncthing") || changed;

// Set password to the API key
Node password = gui.getElementsByTagName("password").item(0);
if (password == null) {
password = mConfig.createElement("password");
gui.appendChild(password);
}
String apikey = getApiKey();
String pw = password.getTextContent();
boolean passwordOk;
try {
passwordOk = !TextUtils.isEmpty(pw) && BCrypt.checkpw(apikey, pw);
} catch (IllegalArgumentException e) {
Log.w(TAG, "Malformed password", e);
passwordOk = false;
}
if (!passwordOk) {
Log.i(TAG, "Updating password");
password.setTextContent(BCrypt.hashpw(apikey, BCrypt.gensalt(4)));
changed = true;
}

/* Section - options */
Element options = (Element) mConfig.getDocumentElement()
.getElementsByTagName("options").item(0);
Expand All @@ -327,12 +322,13 @@ private void updateIfNeeded() {
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node.getNodeName().equals("unackedNotificationID")) {
switch (getContentOrDefault(node, "")) {
String notificationType = getContentOrDefault(node, "");
switch (notificationType) {
case "authenticationUserAndPassword":
case "crAutoEnabled":
case "crAutoDisabled":
case "fsWatcherNotification":
Log.i(TAG, "Remove found unackedNotificationID '" + node + "'.");
Log.i(TAG, "Remove found unackedNotificationID '" + notificationType + "'.");
options.removeChild(node);
changed = true;
break;
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,10 @@ Please report any problems you encounter via Github.</string>

<string name="webui_remote_access_title">Web UI remote access</string>

<string name="webui_username_title">Web UI Username</string>

<string name="webui_password_title">Web UI Password</string>

<string name="webui_remote_access_summary">Specify to permit accessing the Web UI from another device. If enabled, you are able to logon with user \'syncthing\' and API key as password. Default: disabled (most secure)</string>

<string name="webui_debugging_title">WebUI Debugging</string>
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/res/xml/app_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,22 @@
android:singleLineTitle="false"
android:persistent="false" />

<EditTextPreference
android:key="webui_username"
android:title="@string/webui_username_title"
android:singleLineTitle="false"
android:summary="@null"
android:persistent="false"
android:inputType="textNoSuggestions" />

<EditTextPreference
android:key="webui_password"
android:title="@string/webui_password_title"
android:singleLineTitle="false"
android:summary="@null"
android:persistent="true"
android:inputType="textNoSuggestions" />

<Preference
android:persistent="false"
android:selectable="true"
Expand Down
8 changes: 8 additions & 0 deletions debug_scripts/adb_delete_config_xml.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@echo off
REM
:loopMe
adb shell su root rm /data/data/com.github.catfriend1.syncthingandroid.debug/files/config.xml
pause
goto :loopMe
REM
goto :eof

0 comments on commit c0fe2ee

Please sign in to comment.