Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>master
@@ -2,20 +2,14 @@ | |||
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. | |||
* SPDX-License-Identifier: Apache-2.0 | |||
*/ | |||
package com.wireguard.android.configStore | |||
package com.wireguard.android.configStore; | |||
import com.wireguard.config.Config; | |||
import com.wireguard.util.NonNullForAll; | |||
import java.util.Set; | |||
import com.wireguard.config.Config | |||
/** | |||
* Interface for persistent storage providers for WireGuard configurations. | |||
*/ | |||
@NonNullForAll | |||
public interface ConfigStore { | |||
interface ConfigStore { | |||
/** | |||
* Create a persistent tunnel, which must have a unique name within the persistent storage | |||
* medium. | |||
@@ -24,46 +18,51 @@ public interface ConfigStore { | |||
* @param config Configuration for the new tunnel. | |||
* @return The configuration that was actually saved to persistent storage. | |||
*/ | |||
Config create(final String name, final Config config) throws Exception; | |||
@Throws(Exception::class) | |||
fun create(name: String, config: Config): Config | |||
/** | |||
* Delete a persistent tunnel. | |||
* | |||
* @param name The name of the tunnel to delete. | |||
*/ | |||
void delete(final String name) throws Exception; | |||
@Throws(Exception::class) | |||
fun delete(name: String) | |||
/** | |||
* Enumerate the names of tunnels present in persistent storage. | |||
* | |||
* @return The set of present tunnel names. | |||
*/ | |||
Set<String> enumerate(); | |||
fun enumerate(): Set<String> | |||
/** | |||
* Load the configuration for the tunnel given by {@code name}. | |||
* Load the configuration for the tunnel given by `name`. | |||
* | |||
* @param name The identifier for the configuration in persistent storage (i.e. the name of the | |||
* tunnel). | |||
* tunnel). | |||
* @return An in-memory representation of the configuration loaded from persistent storage. | |||
*/ | |||
Config load(final String name) throws Exception; | |||
@Throws(Exception::class) | |||
fun load(name: String): Config | |||
/** | |||
* Rename the configuration for the tunnel given by {@code name}. | |||
* Rename the configuration for the tunnel given by `name`. | |||
* | |||
* @param name The identifier for the existing configuration in persistent storage. | |||
* @param replacement The new identifier for the configuration in persistent storage. | |||
*/ | |||
void rename(String name, String replacement) throws Exception; | |||
@Throws(Exception::class) | |||
fun rename(name: String, replacement: String) | |||
/** | |||
* Save the configuration for an existing tunnel given by {@code name}. | |||
* Save the configuration for an existing tunnel given by `name`. | |||
* | |||
* @param name The identifier for the configuration in persistent storage (i.e. the name of | |||
* the tunnel). | |||
* the tunnel). | |||
* @param config An updated configuration object for the tunnel. | |||
* @return The configuration that was actually saved to persistent storage. | |||
*/ | |||
Config save(final String name, final Config config) throws Exception; | |||
@Throws(Exception::class) | |||
fun save(name: String, config: Config): Config | |||
} |
@@ -1,105 +0,0 @@ | |||
/* | |||
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. | |||
* SPDX-License-Identifier: Apache-2.0 | |||
*/ | |||
package com.wireguard.android.configStore; | |||
import android.content.Context; | |||
import android.util.Log; | |||
import com.wireguard.android.R; | |||
import com.wireguard.config.BadConfigException; | |||
import com.wireguard.config.Config; | |||
import com.wireguard.util.NonNullForAll; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileNotFoundException; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.nio.charset.StandardCharsets; | |||
import java.util.Set; | |||
import java9.util.stream.Collectors; | |||
import java9.util.stream.Stream; | |||
/** | |||
* Configuration store that uses a {@code wg-quick}-style file for each configured tunnel. | |||
*/ | |||
@NonNullForAll | |||
public final class FileConfigStore implements ConfigStore { | |||
private static final String TAG = "WireGuard/" + FileConfigStore.class.getSimpleName(); | |||
private final Context context; | |||
public FileConfigStore(final Context context) { | |||
this.context = context; | |||
} | |||
@Override | |||
public Config create(final String name, final Config config) throws IOException { | |||
Log.d(TAG, "Creating configuration for tunnel " + name); | |||
final File file = fileFor(name); | |||
if (!file.createNewFile()) | |||
throw new IOException(context.getString(R.string.config_file_exists_error, file.getName())); | |||
try (final FileOutputStream stream = new FileOutputStream(file, false)) { | |||
stream.write(config.toWgQuickString().getBytes(StandardCharsets.UTF_8)); | |||
} | |||
return config; | |||
} | |||
@Override | |||
public void delete(final String name) throws IOException { | |||
Log.d(TAG, "Deleting configuration for tunnel " + name); | |||
final File file = fileFor(name); | |||
if (!file.delete()) | |||
throw new IOException(context.getString(R.string.config_delete_error, file.getName())); | |||
} | |||
@Override | |||
public Set<String> enumerate() { | |||
return Stream.of(context.fileList()) | |||
.filter(name -> name.endsWith(".conf")) | |||
.map(name -> name.substring(0, name.length() - ".conf".length())) | |||
.collect(Collectors.toUnmodifiableSet()); | |||
} | |||
private File fileFor(final String name) { | |||
return new File(context.getFilesDir(), name + ".conf"); | |||
} | |||
@Override | |||
public Config load(final String name) throws BadConfigException, IOException { | |||
try (final FileInputStream stream = new FileInputStream(fileFor(name))) { | |||
return Config.parse(stream); | |||
} | |||
} | |||
@Override | |||
public void rename(final String name, final String replacement) throws IOException { | |||
Log.d(TAG, "Renaming configuration for tunnel " + name + " to " + replacement); | |||
final File file = fileFor(name); | |||
final File replacementFile = fileFor(replacement); | |||
if (!replacementFile.createNewFile()) | |||
throw new IOException(context.getString(R.string.config_exists_error, replacement)); | |||
if (!file.renameTo(replacementFile)) { | |||
if (!replacementFile.delete()) | |||
Log.w(TAG, "Couldn't delete marker file for new name " + replacement); | |||
throw new IOException(context.getString(R.string.config_rename_error, file.getName())); | |||
} | |||
} | |||
@Override | |||
public Config save(final String name, final Config config) throws IOException { | |||
Log.d(TAG, "Saving configuration for tunnel " + name); | |||
final File file = fileFor(name); | |||
if (!file.isFile()) | |||
throw new FileNotFoundException(context.getString(R.string.config_not_found_error, file.getName())); | |||
try (final FileOutputStream stream = new FileOutputStream(file, false)) { | |||
stream.write(config.toWgQuickString().getBytes(StandardCharsets.UTF_8)); | |||
} | |||
return config; | |||
} | |||
} |
@@ -0,0 +1,79 @@ | |||
/* | |||
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. | |||
* SPDX-License-Identifier: Apache-2.0 | |||
*/ | |||
package com.wireguard.android.configStore | |||
import android.content.Context | |||
import android.util.Log | |||
import com.wireguard.android.R | |||
import com.wireguard.config.BadConfigException | |||
import com.wireguard.config.Config | |||
import java.io.File | |||
import java.io.FileInputStream | |||
import java.io.FileNotFoundException | |||
import java.io.FileOutputStream | |||
import java.io.IOException | |||
import java.nio.charset.StandardCharsets | |||
/** | |||
* Configuration store that uses a `wg-quick`-style file for each configured tunnel. | |||
*/ | |||
class FileConfigStore(private val context: Context) : ConfigStore { | |||
@Throws(IOException::class) | |||
override fun create(name: String, config: Config): Config { | |||
Log.d(TAG, "Creating configuration for tunnel $name") | |||
val file = fileFor(name) | |||
if (!file.createNewFile()) throw IOException(context.getString(R.string.config_file_exists_error, file.name)) | |||
FileOutputStream(file, false).use { stream -> stream.write(config.toWgQuickString().toByteArray(StandardCharsets.UTF_8)) } | |||
return config | |||
} | |||
@Throws(IOException::class) | |||
override fun delete(name: String) { | |||
Log.d(TAG, "Deleting configuration for tunnel $name") | |||
val file = fileFor(name) | |||
if (!file.delete()) throw IOException(context.getString(R.string.config_delete_error, file.name)) | |||
} | |||
override fun enumerate(): Set<String> { | |||
return context.fileList() | |||
.filter { it.endsWith(".conf") } | |||
.map { it.substring(0, it.length - ".conf".length) } | |||
.toSet() | |||
} | |||
private fun fileFor(name: String): File { | |||
return File(context.filesDir, "$name.conf") | |||
} | |||
@Throws(BadConfigException::class, IOException::class) | |||
override fun load(name: String): Config { | |||
FileInputStream(fileFor(name)).use { stream -> return Config.parse(stream) } | |||
} | |||
@Throws(IOException::class) | |||
override fun rename(name: String, replacement: String) { | |||
Log.d(TAG, "Renaming configuration for tunnel $name to $replacement") | |||
val file = fileFor(name) | |||
val replacementFile = fileFor(replacement) | |||
if (!replacementFile.createNewFile()) throw IOException(context.getString(R.string.config_exists_error, replacement)) | |||
if (!file.renameTo(replacementFile)) { | |||
if (!replacementFile.delete()) Log.w(TAG, "Couldn't delete marker file for new name $replacement") | |||
throw IOException(context.getString(R.string.config_rename_error, file.name)) | |||
} | |||
} | |||
@Throws(IOException::class) | |||
override fun save(name: String, config: Config): Config { | |||
Log.d(TAG, "Saving configuration for tunnel $name") | |||
val file = fileFor(name) | |||
if (!file.isFile) throw FileNotFoundException(context.getString(R.string.config_not_found_error, file.name)) | |||
FileOutputStream(file, false).use { stream -> stream.write(config.toWgQuickString().toByteArray(StandardCharsets.UTF_8)) } | |||
return config | |||
} | |||
companion object { | |||
private val TAG = "WireGuard/" + FileConfigStore::class.java.simpleName | |||
} | |||
} |