Provide semantically meaningful exceptions for translation
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright © 2018 WireGuard LLC. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.wireguard.config;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.wireguard.crypto.KeyFormatException;
|
||||
|
||||
public class BadConfigException extends Exception {
|
||||
private final Location location;
|
||||
private final Reason reason;
|
||||
private final Section section;
|
||||
@Nullable private final CharSequence text;
|
||||
|
||||
private BadConfigException(final Section section, final Location location,
|
||||
final Reason reason, @Nullable final CharSequence text,
|
||||
@Nullable final Throwable cause) {
|
||||
super(cause);
|
||||
this.section = section;
|
||||
this.location = location;
|
||||
this.reason = reason;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public BadConfigException(final Section section, final Location location,
|
||||
final Reason reason, @Nullable final CharSequence text) {
|
||||
this(section, location, reason, text, null);
|
||||
}
|
||||
|
||||
public BadConfigException(final Section section, final Location location,
|
||||
final KeyFormatException cause) {
|
||||
this(section, location, Reason.INVALID_KEY, null, cause);
|
||||
}
|
||||
|
||||
public BadConfigException(final Section section, final Location location,
|
||||
@Nullable final CharSequence text,
|
||||
final NumberFormatException cause) {
|
||||
this(section, location, Reason.INVALID_NUMBER, text, cause);
|
||||
}
|
||||
|
||||
public BadConfigException(final Section section, final Location location,
|
||||
final ParseException cause) {
|
||||
this(section, location, Reason.INVALID_VALUE, cause.getText(), cause);
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public Reason getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public Section getSection() {
|
||||
return section;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CharSequence getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public enum Location {
|
||||
TOP_LEVEL(""),
|
||||
ADDRESS("Address"),
|
||||
ALLOWED_IPS("AllowedIPs"),
|
||||
DNS("DNS"),
|
||||
ENDPOINT("Endpoint"),
|
||||
EXCLUDED_APPLICATIONS("ExcludedApplications"),
|
||||
LISTEN_PORT("ListenPort"),
|
||||
MTU("MTU"),
|
||||
PERSISTENT_KEEPALIVE("PersistentKeepalive"),
|
||||
PRE_SHARED_KEY("PresharedKey"),
|
||||
PRIVATE_KEY("PrivateKey"),
|
||||
PUBLIC_KEY("PublicKey");
|
||||
|
||||
private final String name;
|
||||
|
||||
Location(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Reason {
|
||||
INVALID_KEY,
|
||||
INVALID_NUMBER,
|
||||
INVALID_VALUE,
|
||||
MISSING_ATTRIBUTE,
|
||||
MISSING_SECTION,
|
||||
MISSING_VALUE,
|
||||
SYNTAX_ERROR,
|
||||
UNKNOWN_ATTRIBUTE,
|
||||
UNKNOWN_SECTION
|
||||
}
|
||||
|
||||
public enum Section {
|
||||
CONFIG("Config"),
|
||||
INTERFACE("Interface"),
|
||||
PEER("Peer");
|
||||
|
||||
private final String name;
|
||||
|
||||
Section(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,10 @@ package com.wireguard.config;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.wireguard.config.BadConfigException.Location;
|
||||
import com.wireguard.config.BadConfigException.Reason;
|
||||
import com.wireguard.config.BadConfigException.Section;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -37,23 +41,27 @@ public final class Config {
|
||||
|
||||
/**
|
||||
* Parses an series of "Interface" and "Peer" sections into a {@code Config}. Throws
|
||||
* {@link ParseException} if the input is not well-formed or contains unparseable sections.
|
||||
* {@link BadConfigException} if the input is not well-formed or contains data that cannot
|
||||
* be parsed.
|
||||
*
|
||||
* @param stream a stream of UTF-8 text that is interpreted as a WireGuard configuration file
|
||||
* @param stream a stream of UTF-8 text that is interpreted as a WireGuard configuration
|
||||
* @return a {@code Config} instance representing the supplied configuration
|
||||
*/
|
||||
public static Config parse(final InputStream stream) throws IOException, ParseException {
|
||||
public static Config parse(final InputStream stream)
|
||||
throws IOException, BadConfigException {
|
||||
return parse(new BufferedReader(new InputStreamReader(stream)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an series of "Interface" and "Peer" sections into a {@code Config}. Throws
|
||||
* {@link ParseException} if the input is not well-formed or contains unparseable sections.
|
||||
* {@link BadConfigException} if the input is not well-formed or contains data that cannot
|
||||
* be parsed.
|
||||
*
|
||||
* @param reader a BufferedReader of UTF-8 text that is interpreted as a WireGuard configuration file
|
||||
* @param reader a BufferedReader of UTF-8 text that is interpreted as a WireGuard configuration
|
||||
* @return a {@code Config} instance representing the supplied configuration
|
||||
*/
|
||||
public static Config parse(final BufferedReader reader) throws IOException, ParseException {
|
||||
public static Config parse(final BufferedReader reader)
|
||||
throws IOException, BadConfigException {
|
||||
final Builder builder = new Builder();
|
||||
final Collection<String> interfaceLines = new ArrayList<>();
|
||||
final Collection<String> peerLines = new ArrayList<>();
|
||||
@@ -80,20 +88,23 @@ public final class Config {
|
||||
inInterfaceSection = false;
|
||||
inPeerSection = true;
|
||||
} else {
|
||||
throw new ParseException("top level", line, "Unknown section name");
|
||||
throw new BadConfigException(Section.CONFIG, Location.TOP_LEVEL,
|
||||
Reason.UNKNOWN_SECTION, line);
|
||||
}
|
||||
} else if (inInterfaceSection) {
|
||||
interfaceLines.add(line);
|
||||
} else if (inPeerSection) {
|
||||
peerLines.add(line);
|
||||
} else {
|
||||
throw new ParseException("top level", line, "Expected [Interface] or [Peer]");
|
||||
throw new BadConfigException(Section.CONFIG, Location.TOP_LEVEL,
|
||||
Reason.UNKNOWN_SECTION, line);
|
||||
}
|
||||
}
|
||||
if (inPeerSection)
|
||||
builder.parsePeer(peerLines);
|
||||
else if (!inInterfaceSection)
|
||||
throw new ParseException("top level", "", "Empty configuration");
|
||||
throw new BadConfigException(Section.CONFIG, Location.TOP_LEVEL,
|
||||
Reason.MISSING_SECTION, null);
|
||||
// Combine all [Interface] sections in the file.
|
||||
builder.parseInterface(interfaceLines);
|
||||
return builder.build();
|
||||
@@ -192,11 +203,13 @@ public final class Config {
|
||||
return new Config(this);
|
||||
}
|
||||
|
||||
public Builder parseInterface(final Iterable<? extends CharSequence> lines) throws ParseException {
|
||||
public Builder parseInterface(final Iterable<? extends CharSequence> lines)
|
||||
throws BadConfigException {
|
||||
return setInterface(Interface.parse(lines));
|
||||
}
|
||||
|
||||
public Builder parsePeer(final Iterable<? extends CharSequence> lines) throws ParseException {
|
||||
public Builder parsePeer(final Iterable<? extends CharSequence> lines)
|
||||
throws BadConfigException {
|
||||
return addPeer(Peer.parse(lines));
|
||||
}
|
||||
|
||||
|
||||
@@ -37,17 +37,18 @@ public final class InetAddresses {
|
||||
* @param address a string representing the IP address
|
||||
* @return an instance of {@link Inet4Address} or {@link Inet6Address}, as appropriate
|
||||
*/
|
||||
public static InetAddress parse(final String address) {
|
||||
public static InetAddress parse(final String address) throws ParseException {
|
||||
if (address.isEmpty())
|
||||
throw new IllegalArgumentException("Empty address");
|
||||
throw new ParseException(InetAddress.class, address, "Empty address");
|
||||
try {
|
||||
return (InetAddress) PARSER_METHOD.invoke(null, address);
|
||||
} catch (final IllegalAccessException | InvocationTargetException e) {
|
||||
final Throwable cause = e.getCause();
|
||||
// Re-throw parsing exceptions with the original type, as callers might try to catch
|
||||
// them. On the other hand, callers cannot be expected to handle reflection failures.
|
||||
throw cause instanceof IllegalArgumentException ?
|
||||
(IllegalArgumentException) cause : new RuntimeException(e);
|
||||
if (cause instanceof IllegalArgumentException)
|
||||
throw new ParseException(InetAddress.class, address, cause);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,9 +42,9 @@ public final class InetEndpoint {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public static InetEndpoint parse(final String endpoint) {
|
||||
public static InetEndpoint parse(final String endpoint) throws ParseException {
|
||||
if (FORBIDDEN_CHARACTERS.matcher(endpoint).find())
|
||||
throw new IllegalArgumentException("Forbidden characters in endpoint");
|
||||
throw new ParseException(InetEndpoint.class, endpoint, "Forbidden characters");
|
||||
final URI uri;
|
||||
try {
|
||||
uri = new URI("wg://" + endpoint);
|
||||
@@ -52,12 +52,12 @@ public final class InetEndpoint {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
if (uri.getPort() < 0)
|
||||
throw new IllegalArgumentException("An endpoint must specify a port (e.g. 51820)");
|
||||
throw new ParseException(InetEndpoint.class, endpoint, "Missing/invalid port number");
|
||||
try {
|
||||
InetAddresses.parse(uri.getHost());
|
||||
// Parsing ths host as a numeric address worked, so we don't need to do DNS lookups.
|
||||
return new InetEndpoint(uri.getHost(), true, uri.getPort());
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
} catch (final ParseException ignored) {
|
||||
// Failed to parse the host as a numeric address, so it must be a DNS hostname/FQDN.
|
||||
return new InetEndpoint(uri.getHost(), false, uri.getPort());
|
||||
}
|
||||
|
||||
@@ -22,19 +22,28 @@ public final class InetNetwork {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
public static InetNetwork parse(final String network) {
|
||||
public static InetNetwork parse(final String network) throws ParseException {
|
||||
final int slash = network.lastIndexOf('/');
|
||||
final String maskString;
|
||||
final int rawMask;
|
||||
final String rawAddress;
|
||||
if (slash >= 0) {
|
||||
rawMask = Integer.parseInt(network.substring(slash + 1), 10);
|
||||
maskString = network.substring(slash + 1);
|
||||
try {
|
||||
rawMask = Integer.parseInt(maskString, 10);
|
||||
} catch (final NumberFormatException ignored) {
|
||||
throw new ParseException(Integer.class, maskString);
|
||||
}
|
||||
rawAddress = network.substring(0, slash);
|
||||
} else {
|
||||
maskString = "";
|
||||
rawMask = -1;
|
||||
rawAddress = network;
|
||||
}
|
||||
final InetAddress address = InetAddresses.parse(rawAddress);
|
||||
final int maxMask = (address instanceof Inet4Address) ? 32 : 128;
|
||||
if (rawMask > maxMask)
|
||||
throw new ParseException(InetNetwork.class, maskString, "Invalid network mask");
|
||||
final int mask = rawMask >= 0 && rawMask <= maxMask ? rawMask : maxMask;
|
||||
return new InetNetwork(address, mask);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,11 @@ package com.wireguard.config;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.wireguard.config.BadConfigException.Location;
|
||||
import com.wireguard.config.BadConfigException.Reason;
|
||||
import com.wireguard.config.BadConfigException.Section;
|
||||
import com.wireguard.crypto.Key;
|
||||
import com.wireguard.crypto.KeyFormatException;
|
||||
import com.wireguard.crypto.KeyPair;
|
||||
|
||||
import java.net.InetAddress;
|
||||
@@ -22,7 +26,6 @@ import java.util.Set;
|
||||
import java9.util.Lists;
|
||||
import java9.util.Optional;
|
||||
import java9.util.stream.Collectors;
|
||||
import java9.util.stream.Stream;
|
||||
import java9.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
@@ -60,11 +63,13 @@ public final class Interface {
|
||||
* @param lines An iterable sequence of lines, containing at least a private key attribute
|
||||
* @return An {@code Interface} with all of the attributes from {@code lines} set
|
||||
*/
|
||||
public static Interface parse(final Iterable<? extends CharSequence> lines) throws ParseException {
|
||||
public static Interface parse(final Iterable<? extends CharSequence> lines)
|
||||
throws BadConfigException {
|
||||
final Builder builder = new Builder();
|
||||
for (final CharSequence line : lines) {
|
||||
final Attribute attribute = Attribute.parse(line)
|
||||
.orElseThrow(() -> new ParseException("[Interface]", line, "Syntax error"));
|
||||
final Attribute attribute = Attribute.parse(line).orElseThrow(() ->
|
||||
new BadConfigException(Section.INTERFACE, Location.TOP_LEVEL,
|
||||
Reason.SYNTAX_ERROR, line));
|
||||
switch (attribute.getKey().toLowerCase(Locale.ENGLISH)) {
|
||||
case "address":
|
||||
builder.parseAddresses(attribute.getValue());
|
||||
@@ -85,7 +90,8 @@ public final class Interface {
|
||||
builder.parsePrivateKey(attribute.getValue());
|
||||
break;
|
||||
default:
|
||||
throw new ParseException("[Interface]", attribute.getKey(), "Unknown attribute");
|
||||
throw new BadConfigException(Section.INTERFACE, Location.TOP_LEVEL,
|
||||
Reason.UNKNOWN_ATTRIBUTE, attribute.getKey());
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
@@ -260,9 +266,10 @@ public final class Interface {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Interface build() {
|
||||
public Interface build() throws BadConfigException {
|
||||
if (keyPair == null)
|
||||
throw new IllegalArgumentException("Interfaces must have a private key");
|
||||
throw new BadConfigException(Section.INTERFACE, Location.PRIVATE_KEY,
|
||||
Reason.MISSING_ATTRIBUTE, null);
|
||||
return new Interface(this);
|
||||
}
|
||||
|
||||
@@ -276,57 +283,51 @@ public final class Interface {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder parseAddresses(final CharSequence addresses) throws ParseException {
|
||||
public Builder parseAddresses(final CharSequence addresses) throws BadConfigException {
|
||||
try {
|
||||
final List<InetNetwork> parsed = Stream.of(Attribute.split(addresses))
|
||||
.map(InetNetwork::parse)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
return addAddresses(parsed);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new ParseException("Address", addresses, e);
|
||||
for (final String address : Attribute.split(addresses))
|
||||
addAddress(InetNetwork.parse(address));
|
||||
return this;
|
||||
} catch (final ParseException e) {
|
||||
throw new BadConfigException(Section.INTERFACE, Location.ADDRESS, e);
|
||||
}
|
||||
}
|
||||
|
||||
public Builder parseDnsServers(final CharSequence dnsServers) throws ParseException {
|
||||
public Builder parseDnsServers(final CharSequence dnsServers) throws BadConfigException {
|
||||
try {
|
||||
final List<InetAddress> parsed = Stream.of(Attribute.split(dnsServers))
|
||||
.map(InetAddresses::parse)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
return addDnsServers(parsed);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new ParseException("DNS", dnsServers, e);
|
||||
for (final String dnsServer : Attribute.split(dnsServers))
|
||||
addDnsServer(InetAddresses.parse(dnsServer));
|
||||
return this;
|
||||
} catch (final ParseException e) {
|
||||
throw new BadConfigException(Section.INTERFACE, Location.DNS, e);
|
||||
}
|
||||
}
|
||||
|
||||
public Builder parseExcludedApplications(final CharSequence apps) throws ParseException {
|
||||
try {
|
||||
return excludeApplications(Lists.of(Attribute.split(apps)));
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new ParseException("ExcludedApplications", apps, e);
|
||||
}
|
||||
public Builder parseExcludedApplications(final CharSequence apps) {
|
||||
return excludeApplications(Lists.of(Attribute.split(apps)));
|
||||
}
|
||||
|
||||
public Builder parseListenPort(final String listenPort) throws ParseException {
|
||||
public Builder parseListenPort(final String listenPort) throws BadConfigException {
|
||||
try {
|
||||
return setListenPort(Integer.parseInt(listenPort));
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new ParseException("ListenPort", listenPort, e);
|
||||
} catch (final NumberFormatException e) {
|
||||
throw new BadConfigException(Section.INTERFACE, Location.LISTEN_PORT, listenPort, e);
|
||||
}
|
||||
}
|
||||
|
||||
public Builder parseMtu(final String mtu) throws ParseException {
|
||||
public Builder parseMtu(final String mtu) throws BadConfigException {
|
||||
try {
|
||||
return setMtu(Integer.parseInt(mtu));
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new ParseException("MTU", mtu, e);
|
||||
} catch (final NumberFormatException e) {
|
||||
throw new BadConfigException(Section.INTERFACE, Location.MTU, mtu, e);
|
||||
}
|
||||
}
|
||||
|
||||
public Builder parsePrivateKey(final String privateKey) throws ParseException {
|
||||
public Builder parsePrivateKey(final String privateKey) throws BadConfigException {
|
||||
try {
|
||||
return setKeyPair(new KeyPair(Key.fromBase64(privateKey)));
|
||||
} catch (final Key.KeyFormatException e) {
|
||||
throw new ParseException("PrivateKey", "(omitted)", e);
|
||||
} catch (final KeyFormatException e) {
|
||||
throw new BadConfigException(Section.INTERFACE, Location.PRIVATE_KEY, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,16 +336,18 @@ public final class Interface {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setListenPort(final int listenPort) {
|
||||
public Builder setListenPort(final int listenPort) throws BadConfigException {
|
||||
if (listenPort < MIN_UDP_PORT || listenPort > MAX_UDP_PORT)
|
||||
throw new IllegalArgumentException("ListenPort must be a valid UDP port number");
|
||||
throw new BadConfigException(Section.INTERFACE, Location.LISTEN_PORT,
|
||||
Reason.INVALID_VALUE, String.valueOf(listenPort));
|
||||
this.listenPort = listenPort == 0 ? Optional.empty() : Optional.of(listenPort);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setMtu(final int mtu) {
|
||||
public Builder setMtu(final int mtu) throws BadConfigException {
|
||||
if (mtu < 0)
|
||||
throw new IllegalArgumentException("MTU must not be negative");
|
||||
throw new BadConfigException(Section.INTERFACE, Location.LISTEN_PORT,
|
||||
Reason.INVALID_VALUE, String.valueOf(mtu));
|
||||
this.mtu = mtu == 0 ? Optional.empty() : Optional.of(mtu);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -5,34 +5,37 @@
|
||||
|
||||
package com.wireguard.config;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An exception representing a failure to parse an element of a WireGuard configuration. The context
|
||||
* for this failure can be retrieved with {@link #getContext}, and the text that failed to parse can
|
||||
* be retrieved with {@link #getText}.
|
||||
*/
|
||||
public class ParseException extends Exception {
|
||||
private final String context;
|
||||
private final Class<?> parsingClass;
|
||||
private final CharSequence text;
|
||||
|
||||
public ParseException(final String context, final CharSequence text, final String message) {
|
||||
super(message);
|
||||
this.context = context;
|
||||
public ParseException(final Class<?> parsingClass, final CharSequence text,
|
||||
@Nullable final String message, @Nullable final Throwable cause) {
|
||||
super(message, cause);
|
||||
this.parsingClass = parsingClass;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public ParseException(final String context, final CharSequence text, final Throwable cause) {
|
||||
super(cause.getMessage(), cause);
|
||||
this.context = context;
|
||||
this.text = text;
|
||||
public ParseException(final Class<?> parsingClass, final CharSequence text,
|
||||
@Nullable final String message) {
|
||||
this(parsingClass, text, message, null);
|
||||
}
|
||||
|
||||
public ParseException(final String context, final CharSequence text) {
|
||||
this.context = context;
|
||||
this.text = text;
|
||||
public ParseException(final Class<?> parsingClass, final CharSequence text,
|
||||
@Nullable final Throwable cause) {
|
||||
this(parsingClass, text, null, cause);
|
||||
}
|
||||
|
||||
public String getContext() {
|
||||
return context;
|
||||
public ParseException(final Class<?> parsingClass, final CharSequence text) {
|
||||
this(parsingClass, text, null, null);
|
||||
}
|
||||
|
||||
public Class<?> getParsingClass() {
|
||||
return parsingClass;
|
||||
}
|
||||
|
||||
public CharSequence getText() {
|
||||
|
||||
@@ -7,19 +7,20 @@ package com.wireguard.config;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.wireguard.config.BadConfigException.Location;
|
||||
import com.wireguard.config.BadConfigException.Reason;
|
||||
import com.wireguard.config.BadConfigException.Section;
|
||||
import com.wireguard.crypto.Key;
|
||||
import com.wireguard.crypto.KeyFormatException;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import java9.util.Optional;
|
||||
import java9.util.stream.Collectors;
|
||||
import java9.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Represents the configuration for a WireGuard peer (a [Peer] block). Peers must have a public key,
|
||||
@@ -50,11 +51,13 @@ public final class Peer {
|
||||
* @param lines an iterable sequence of lines, containing at least a public key attribute
|
||||
* @return a {@code Peer} with all of its attributes set from {@code lines}
|
||||
*/
|
||||
public static Peer parse(final Iterable<? extends CharSequence> lines) throws ParseException {
|
||||
public static Peer parse(final Iterable<? extends CharSequence> lines)
|
||||
throws BadConfigException {
|
||||
final Builder builder = new Builder();
|
||||
for (final CharSequence line : lines) {
|
||||
final Attribute attribute = Attribute.parse(line)
|
||||
.orElseThrow(() -> new ParseException("[Peer]", line, "Syntax error"));
|
||||
final Attribute attribute = Attribute.parse(line).orElseThrow(() ->
|
||||
new BadConfigException(Section.PEER, Location.TOP_LEVEL,
|
||||
Reason.SYNTAX_ERROR, line));
|
||||
switch (attribute.getKey().toLowerCase(Locale.ENGLISH)) {
|
||||
case "allowedips":
|
||||
builder.parseAllowedIPs(attribute.getValue());
|
||||
@@ -72,7 +75,8 @@ public final class Peer {
|
||||
builder.parsePublicKey(attribute.getValue());
|
||||
break;
|
||||
default:
|
||||
throw new ParseException("[Peer]", line, "Unknown attribute");
|
||||
throw new BadConfigException(Section.PEER, Location.TOP_LEVEL,
|
||||
Reason.UNKNOWN_ATTRIBUTE, attribute.getKey());
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
@@ -223,52 +227,54 @@ public final class Peer {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Peer build() {
|
||||
public Peer build() throws BadConfigException {
|
||||
if (publicKey == null)
|
||||
throw new IllegalArgumentException("Peers must have a public key");
|
||||
throw new BadConfigException(Section.PEER, Location.PUBLIC_KEY,
|
||||
Reason.MISSING_ATTRIBUTE, null);
|
||||
return new Peer(this);
|
||||
}
|
||||
|
||||
public Builder parseAllowedIPs(final CharSequence allowedIps) throws ParseException {
|
||||
public Builder parseAllowedIPs(final CharSequence allowedIps) throws BadConfigException {
|
||||
try {
|
||||
final List<InetNetwork> parsed = Stream.of(Attribute.split(allowedIps))
|
||||
.map(InetNetwork::parse)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
return addAllowedIps(parsed);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new ParseException("AllowedIPs", allowedIps, e);
|
||||
for (final String allowedIp : Attribute.split(allowedIps))
|
||||
addAllowedIp(InetNetwork.parse(allowedIp));
|
||||
return this;
|
||||
} catch (final ParseException e) {
|
||||
throw new BadConfigException(Section.PEER, Location.ALLOWED_IPS, e);
|
||||
}
|
||||
}
|
||||
|
||||
public Builder parseEndpoint(final String endpoint) throws ParseException {
|
||||
public Builder parseEndpoint(final String endpoint) throws BadConfigException {
|
||||
try {
|
||||
return setEndpoint(InetEndpoint.parse(endpoint));
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new ParseException("Endpoint", endpoint, e);
|
||||
} catch (final ParseException e) {
|
||||
throw new BadConfigException(Section.PEER, Location.ENDPOINT, e);
|
||||
}
|
||||
}
|
||||
|
||||
public Builder parsePersistentKeepalive(final String persistentKeepalive) throws ParseException {
|
||||
public Builder parsePersistentKeepalive(final String persistentKeepalive)
|
||||
throws BadConfigException {
|
||||
try {
|
||||
return setPersistentKeepalive(Integer.parseInt(persistentKeepalive));
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new ParseException("PersistentKeepalive", persistentKeepalive, e);
|
||||
} catch (final NumberFormatException e) {
|
||||
throw new BadConfigException(Section.PEER, Location.PERSISTENT_KEEPALIVE,
|
||||
persistentKeepalive, e);
|
||||
}
|
||||
}
|
||||
|
||||
public Builder parsePreSharedKey(final String preSharedKey) throws ParseException {
|
||||
public Builder parsePreSharedKey(final String preSharedKey) throws BadConfigException {
|
||||
try {
|
||||
return setPreSharedKey(Key.fromBase64(preSharedKey));
|
||||
} catch (final Key.KeyFormatException e) {
|
||||
throw new ParseException("PresharedKey", preSharedKey, e);
|
||||
} catch (final KeyFormatException e) {
|
||||
throw new BadConfigException(Section.PEER, Location.PRE_SHARED_KEY, e);
|
||||
}
|
||||
}
|
||||
|
||||
public Builder parsePublicKey(final String publicKey) throws ParseException {
|
||||
public Builder parsePublicKey(final String publicKey) throws BadConfigException {
|
||||
try {
|
||||
return setPublicKey(Key.fromBase64(publicKey));
|
||||
} catch (final Key.KeyFormatException e) {
|
||||
throw new ParseException("PublicKey", publicKey, e);
|
||||
} catch (final KeyFormatException e) {
|
||||
throw new BadConfigException(Section.PEER, Location.PUBLIC_KEY, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,9 +283,11 @@ public final class Peer {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPersistentKeepalive(final int persistentKeepalive) {
|
||||
public Builder setPersistentKeepalive(final int persistentKeepalive)
|
||||
throws BadConfigException {
|
||||
if (persistentKeepalive < 0 || persistentKeepalive > MAX_PERSISTENT_KEEPALIVE)
|
||||
throw new IllegalArgumentException("Invalid value for PersistentKeepalive");
|
||||
throw new BadConfigException(Section.PEER, Location.PERSISTENT_KEEPALIVE,
|
||||
Reason.INVALID_VALUE, String.valueOf(persistentKeepalive));
|
||||
this.persistentKeepalive = persistentKeepalive == 0 ?
|
||||
Optional.empty() : Optional.of(persistentKeepalive);
|
||||
return this;
|
||||
|
||||
Reference in New Issue
Block a user