Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,28 @@ manifest can call the config plugin instead, which adds the same entries:
}
```

## Encrypted export

`encryptExport` turns an app-defined JSON payload into an
[age](https://age-encryption.org) file encrypted to a passphrase, so a backup can
be moved between devices by any means. `decryptExport` opens files that this
library or `age -p -a` produced. Both run the scrypt key derivation in the Rust
core on a native worker, off the JavaScript thread.

```ts
const file = await encryptExport(JSON.stringify(backup), passphrase);
await FileSystem.writeAsStringAsync(path, file);

const backup = JSON.parse(await decryptExport(await readAsStringAsync(path), passphrase));
```

Rejections carry a `code`:

| `code` | Cause |
| --- | --- |
| `WrongPassphrase` | The passphrase does not open the file. |
| `InvalidExport` | The payload exceeds 16 MiB, the passphrase is shorter than 8 characters when encrypting, or the input is not an intact age file. |

## License

Apache-2.0. See [LICENSE](./LICENSE).
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import ai.kilo.reactnativessh.uniffi.SshSession
import ai.kilo.reactnativessh.uniffi.TransferProgress
import ai.kilo.reactnativessh.uniffi.categoryIsRetryable
import ai.kilo.reactnativessh.uniffi.coreVersion
import ai.kilo.reactnativessh.uniffi.decryptExport
import ai.kilo.reactnativessh.uniffi.encryptExport
import ai.kilo.reactnativessh.uniffi.generateEd25519Key
import ai.kilo.reactnativessh.uniffi.parsePrivateKey
import android.content.Context
Expand Down Expand Up @@ -92,6 +94,14 @@ class ReactNativeSshModule : Module() {
)
}

AsyncFunction("encryptExport") { plaintextJson: String, passphrase: String ->
translateFailures { encryptExport(plaintextJson, passphrase) }
}

AsyncFunction("decryptExport") { armored: String, passphrase: String ->
translateFailures { decryptExport(armored, passphrase) }
}

AsyncFunction("connect").SuspendBody { config: ConnectConfigRecord ->
connectSession(config) { handler -> SshSession.connect(config.toNative(), handler) }
}
Expand Down
1 change: 1 addition & 0 deletions android/src/main/java/ai/kilo/reactnativessh/SshErrors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ private fun SshException.code(): String = when (this) {
is SshException.UnsupportedAlgorithm -> "UnsupportedAlgorithm"
is SshException.KeyParse -> "KeyParse"
is SshException.WrongPassphrase -> "WrongPassphrase"
is SshException.InvalidExport -> "InvalidExport"
is SshException.ChannelClosed -> "ChannelClosed"
is SshException.Protocol -> "Protocol"
is SshException.KeyGeneration -> "KeyGeneration"
Expand Down
8 changes: 8 additions & 0 deletions ios/ReactNativeSshModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ public final class ReactNativeSshModule: Module {
)
}

AsyncFunction("encryptExport") { (plaintextJson: String, passphrase: String) throws -> String in
try translate { try encryptExport(plaintextJson: plaintextJson, passphrase: passphrase) }
}

AsyncFunction("decryptExport") { (armored: String, passphrase: String) throws -> String in
try translate { try decryptExport(armored: armored, passphrase: passphrase) }
}

AsyncFunction("connect") { (config: ConnectConfigRecord) async throws -> String in
try await self.connectSession(config)
}
Expand Down
3 changes: 3 additions & 0 deletions ios/SshErrors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ extension SshError {
return "KeyParse"
case .WrongPassphrase:
return "WrongPassphrase"
case .InvalidExport:
return "InvalidExport"
case .ChannelClosed:
return "ChannelClosed"
case .Protocol:
Expand All @@ -51,6 +53,7 @@ extension SshError {
.AuthFailed(let message),
.UnsupportedAlgorithm(let message),
.KeyParse(let message),
.InvalidExport(let message),
.ChannelClosed(let message),
.Protocol(let message),
.KeyGeneration(let message),
Expand Down
Loading
Loading