Added warning about local network access

master
M66B 1 day ago
parent 53020d277a
commit b48bb38b5d

@ -455,6 +455,7 @@ Anything on this list is in random order and *might* be added in the near future
* [(207) What does 'Authentication failed' mean?](#faq207)
* [(208) What does 'about:blank#blocked' mean when I click on a link?](#faq208)
* [(209) Why is using a VPN often problematic?](#faq209)
* [(210) Why are local network permissions needed?](#faq210)
[I have another question.](#get-support)
@ -6508,6 +6509,24 @@ This is also why the app warns against using a VPN.
<br>
<a name="faq210"></a>
**(210) Why are local network permissions needed?**
&#x1F30E; [Google Translate](https://translate.google.com/translate?sl=en&u=https%3A%2F%2Fm66b.github.io%2FFairEmail%2F%23faq210)
Since Android 17, Android requires [local network permission](https://developer.android.com/privacy-and-security/local-network-permission) for local network access (LAN access).
This permission can be granted via a button on the connection settings page.
Very few people will need LAN access, and to avoid questions regarding a new permission, this permission is available only in the [GitHub version](https://github.com/M66B/FairEmail/releases).
If the app navigated to this FAQ after you clicked the button to grant local network permissions, then the GitHub version is not (or is no longer) installed.
Added in version 1.2325.
<br>
<h2><a name="get-support"></a>Get support</h2>
&#x1F30E; [Google Translate](https://translate.google.com/translate?sl=en&u=https%3A%2F%2Fm66b.github.io%2FFairEmail%2F%23get-support)

@ -74,6 +74,7 @@ import com.google.android.material.textfield.TextInputLayout;
import org.json.JSONObject;
import java.io.FileNotFoundException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
@ -335,6 +336,7 @@ public class FragmentAccount extends FragmentBase {
adapterView.setTag(position);
etHost.setText(provider.imap.host);
checkLan(provider.imap.host);
etPort.setText(provider.imap.host == null ? null : Integer.toString(provider.imap.port));
rgEncryption.check(provider.imap.starttls ? R.id.radio_starttls : R.id.radio_ssl);
@ -372,6 +374,23 @@ public class FragmentAccount extends FragmentBase {
}
});
etHost.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
checkLan(s == null ? null : s.toString());
}
});
rgEncryption.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int id) {
@ -749,6 +768,7 @@ public class FragmentAccount extends FragmentBase {
@Override
protected void onExecuted(Bundle args, EmailProvider provider) {
etHost.setText(provider.imap.host);
checkLan(provider.imap.host);
etPort.setText(Integer.toString(provider.imap.port));
rgEncryption.check(provider.imap.starttls ? R.id.radio_starttls : R.id.radio_ssl);
}
@ -1749,6 +1769,7 @@ public class FragmentAccount extends FragmentBase {
spProvider.setSelection(1);
}
etHost.setText(account.host);
checkLan(account.host);
etPort.setText(Long.toString(account.port));
}
@ -2146,6 +2167,21 @@ public class FragmentAccount extends FragmentBase {
}.execute(this, args, "account:delete");
}
private void checkLan(String host) {
String msg = null;
if (!TextUtils.isEmpty(host))
try {
Context context = getContext();
InetAddress addr = InetAddress.getByName(host);
if ((addr.isSiteLocalAddress() || addr.isLinkLocalAddress() || addr.isLoopbackAddress()) &&
!Helper.hasPermission(context, Manifest.permission.ACCESS_LOCAL_NETWORK))
msg = context.getString(R.string.title_lan);
} catch (Throwable ignored) {
}
etHost.setError(msg);
}
private void setFolders(List<EntityFolder> _folders, EntityAccount account) {
{
List<EntityFolder> folders = new ArrayList<>();

@ -69,6 +69,7 @@ import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.textfield.TextInputLayout;
import java.io.FileNotFoundException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
@ -310,10 +311,13 @@ public class FragmentIdentity extends FragmentBase {
spProvider.setTag(0);
spProvider.setSelection(0);
setProvider((EmailProvider) spProvider.getItemAtPosition(0));
if (account.host == null || account.host.startsWith("imap"))
if (account.host == null || account.host.startsWith("imap")) {
etHost.setText(null);
else
checkLan(null);
} else {
etHost.setText(account.host);
checkLan(account.host);
}
grpAdvanced.setVisibility(View.VISIBLE);
}
@ -463,6 +467,23 @@ public class FragmentIdentity extends FragmentBase {
}
});
etHost.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
checkLan(s == null ? null : s.toString());
}
});
rgEncryption.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int id) {
@ -691,6 +712,7 @@ public class FragmentIdentity extends FragmentBase {
private void setProvider(EmailProvider provider) {
etHost.setText(provider.smtp.host);
checkLan(provider.smtp.host);
etPort.setText(provider.smtp.port == 0 ? null : Integer.toString(provider.smtp.port));
rgEncryption.check(provider.smtp.starttls ? R.id.radio_starttls : R.id.radio_ssl);
cbUseIp.setChecked(provider.useip);
@ -730,6 +752,7 @@ public class FragmentIdentity extends FragmentBase {
@Override
protected void onExecuted(Bundle args, EmailProvider provider) {
etHost.setText(provider.smtp.host);
checkLan(provider.smtp.host);
etPort.setText(Integer.toString(provider.smtp.port));
rgEncryption.check(provider.smtp.starttls ? R.id.radio_starttls : R.id.radio_ssl);
cbUseIp.setChecked(provider.useip);
@ -1353,6 +1376,7 @@ public class FragmentIdentity extends FragmentBase {
cbDnsSec.setChecked(identity == null ? false : identity.dnssec);
etHost.setText(identity == null ? null : identity.host);
checkLan(identity == null ? null : identity.host);
if (identity != null && identity.encryption == EmailService.ENCRYPTION_STARTTLS)
rgEncryption.check(R.id.radio_starttls);
@ -1684,6 +1708,21 @@ public class FragmentIdentity extends FragmentBase {
}.execute(this, args, "identity:signature");
}
private void checkLan(String host) {
String msg = null;
if (!TextUtils.isEmpty(host))
try {
Context context = getContext();
InetAddress addr = InetAddress.getByName(host);
if ((addr.isSiteLocalAddress() || addr.isLinkLocalAddress() || addr.isLoopbackAddress()) &&
!Helper.hasPermission(context, Manifest.permission.ACCESS_LOCAL_NETWORK))
msg = context.getString(R.string.title_lan);
} catch (Throwable ignored) {
}
etHost.setError(msg);
}
private void onPickUri(Intent intent) {
Uri uri = (intent == null ? null : intent.getData());
btnUri.setTag(uri == null ? null : uri.toString());

@ -513,13 +513,16 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre
}
});
btnLocalNetwork.setVisibility(BuildConfig.PLAY_STORE_RELEASE || Build.VERSION.SDK_INT < Build.VERSION_CODES.CINNAMON_BUN
btnLocalNetwork.setVisibility(Build.VERSION.SDK_INT < Build.VERSION_CODES.CINNAMON_BUN
? View.GONE : View.VISIBLE);
btnLocalNetwork.setEnabled(!Helper.hasPermission(getContext(), Manifest.permission.ACCESS_LOCAL_NETWORK));
btnLocalNetwork.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
requestPermissions(new String[]{Manifest.permission.ACCESS_LOCAL_NETWORK}, REQUEST_PERMISSIONS);
if (BuildConfig.PLAY_STORE_RELEASE)
Helper.viewFAQ(v.getContext(), 210);
else
requestPermissions(new String[]{Manifest.permission.ACCESS_LOCAL_NETWORK}, REQUEST_PERMISSIONS);
}
});

@ -65,6 +65,7 @@ import com.google.android.material.textfield.TextInputLayout;
import org.json.JSONObject;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@ -224,6 +225,23 @@ public class FragmentPop extends FragmentBase {
this.colorWarning = Helper.resolveColor(getContext(), R.attr.colorWarning);
this.textColorSecondary = Helper.resolveColor(getContext(), android.R.attr.textColorSecondary);
etHost.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
checkLan(s == null ? null : s.toString());
}
});
rgEncryption.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int id) {
@ -938,6 +956,7 @@ public class FragmentPop extends FragmentBase {
cbDnsSec.setChecked(account == null ? false : account.dnssec);
etHost.setText(account == null ? null : account.host);
checkLan(account == null ? null : account.host);
etPort.setText(account == null ? null : Long.toString(account.port));
if (account != null && account.encryption == EmailService.ENCRYPTION_STARTTLS)
@ -1206,6 +1225,21 @@ public class FragmentPop extends FragmentBase {
}.execute(this, args, "account:delete");
}
private void checkLan(String host) {
String msg = null;
if (!TextUtils.isEmpty(host))
try {
Context context = getContext();
InetAddress addr = InetAddress.getByName(host);
if ((addr.isSiteLocalAddress() || addr.isLinkLocalAddress() || addr.isLoopbackAddress()) &&
!Helper.hasPermission(context, Manifest.permission.ACCESS_LOCAL_NETWORK))
msg = context.getString(R.string.title_lan);
} catch (Throwable ignored) {
}
etHost.setError(msg);
}
private List<EntityFolder> getSwipeActions(Context context) {
List<EntityFolder> folders = new ArrayList<>();

@ -1302,6 +1302,7 @@
<string name="title_imap" translatable="false">IMAP</string>
<string name="title_pop3" translatable="false">POP3</string>
<string name="title_smtp" translatable="false">SMTP</string>
<string name="title_lan">Local network permissions must be granted on the connection settings tab page</string>
<string name="title_aliases">Aliases</string>
<string name="title_provider">Provider</string>
<string name="title_custom">Custom</string>

@ -443,6 +443,7 @@
<li><a href="#faq207">(207) What does Authentication failed mean?</a></li>
<li><a href="#faq208">(208) What does about:blank#blocked mean when I click on a link?</a></li>
<li><a href="#faq209">(209) Why is using a VPN often problematic?</a></li>
<li><a href="#faq210">(210) Why are local network permissions needed?</a></li>
</ul>
<p><a href="#get-support">I have another question.</a></p>
<p><a name="faq1"></a> <strong>(1) Which permissions are needed and why?</strong></p>
@ -3246,6 +3247,14 @@ adb install /path/to/FairEmail-xxx.apk</code></pre>
<p>🌎 <a href="https://translate.google.com/translate?sl=en&amp;u=https%3A%2F%2Fm66b.github.io%2FFairEmail%2F%23faq209">Google Translate</a></p>
<p>When you use a VPN, you share one network address with many people and not all those people will always behave nicely. Email servers often automatically block network addresses (IP addresses) when abuse is detected, for example when someone tries to send spam messages. The result is that logins are blocked for everyone using the same network address and the email server issues an error message such as “<em>Authentication failed</em>”. This is also why the app warns against using a VPN.</p>
<p><br></p>
<p><a name="faq210"></a> <strong>(210) Why are local network permissions needed?</strong></p>
<p>🌎 <a href="https://translate.google.com/translate?sl=en&amp;u=https%3A%2F%2Fm66b.github.io%2FFairEmail%2F%23faq210">Google Translate</a></p>
<p>Since Android 17, Android requires <a href="https://developer.android.com/privacy-and-security/local-network-permission">local network permission</a> for local network access (LAN access).</p>
<p>This permission can be granted via a button on the connection settings page.</p>
<p>Very few people will need LAN access, and to avoid questions regarding a new permission, this permission is available only in the <a href="https://github.com/M66B/FairEmail/releases">GitHub version</a>.</p>
<p>If the app navigated to this FAQ after you clicked the button to grant local network permissions, then the GitHub version is not (or is no longer) installed.</p>
<p>Added in version 1.2325.</p>
<p><br></p>
<h2>
<a name="get-support"></a>Get support
</h2>

Loading…
Cancel
Save