mirror of
https://github.com/aljazceru/react-native-pubky.git
synced 2025-12-18 23:24:22 +01:00
Merge pull request #10 from pubky/publish-resolve-https
feat: add publish_https & resolve_https
This commit is contained in:
32
README.md
32
README.md
@@ -14,6 +14,8 @@ npm install @synonymdev/react-native-pubky
|
||||
- [x] [parseAuthUrl](#parseAuthUrl): Method to decode an authUrl.
|
||||
- [x] [publish](#publish): Functionality to publish content.
|
||||
- [x] [resolve](#resolve): Functionality to resolve content.
|
||||
- [x] [publishHttps](#publishHttps): Publish HTTPS records.
|
||||
- [x] [resolveHttps](#resolveHttps): Resolve HTTPS records.
|
||||
### Methods to be Implemented
|
||||
- [ ] signIn: Sign-in to a homeserver.
|
||||
- [ ] signUp: Sign-up to a homeserver and update Pkarr accordingly.
|
||||
@@ -78,6 +80,36 @@ if (resolveRes.isErr()) {
|
||||
console.log(resolveRes.value);
|
||||
```
|
||||
|
||||
### <a name="publishHttps"></a>publishHttps
|
||||
```js
|
||||
import { publishHttps } from '@synonymdev/react-native-pubky';
|
||||
|
||||
const publishHttpsRes = await publishHttps(
|
||||
'example.com', // Record Name
|
||||
'target.example.com', // Target
|
||||
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' // Secret Key
|
||||
);
|
||||
if (publishHttpsRes.isErr()) {
|
||||
console.log(publishHttpsRes.error.message);
|
||||
return;
|
||||
}
|
||||
console.log(publishHttpsRes.value);
|
||||
```
|
||||
|
||||
### <a name="resolveHttps"></a>resolveHttps
|
||||
```js
|
||||
import { resolveHttps } from '@synonymdev/react-native-pubky';
|
||||
|
||||
const resolveHttpsRes = await resolveHttps(
|
||||
'z4e8s17cou9qmuwen8p1556jzhf1wktmzo6ijsfnri9c4hnrdfty' // Public key
|
||||
);
|
||||
if (resolveHttpsRes.isErr()) {
|
||||
console.log(resolveHttpsRes.error.message);
|
||||
return;
|
||||
}
|
||||
console.log(resolveHttpsRes.value);
|
||||
```
|
||||
|
||||
## Local Installation
|
||||
|
||||
1. Clone & npm install:
|
||||
|
||||
@@ -18,6 +18,8 @@ import uniffi.pubkymobile.signIn
|
||||
import uniffi.pubkymobile.signOut
|
||||
import uniffi.pubkymobile.put
|
||||
import uniffi.pubkymobile.get
|
||||
import uniffi.pubkymobile.publishHttps
|
||||
import uniffi.pubkymobile.resolveHttps
|
||||
|
||||
class PubkyModule(reactContext: ReactApplicationContext) :
|
||||
ReactContextBaseJavaModule(reactContext) {
|
||||
@@ -191,6 +193,44 @@ class PubkyModule(reactContext: ReactApplicationContext) :
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun publishHttps(recordName: String, target: String, secretKey: String, promise: Promise) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val result = publishHttps(recordName, target, secretKey)
|
||||
val array = Arguments.createArray().apply {
|
||||
result.forEach { pushString(it) }
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
promise.resolve(array)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
promise.reject("Error", e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun resolveHttps(publicKey: String, promise: Promise) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val result = resolveHttps(publicKey)
|
||||
val array = Arguments.createArray().apply {
|
||||
result.forEach { pushString(it) }
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
promise.resolve(array)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
promise.reject("Error", e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val NAME = "Pubky"
|
||||
}
|
||||
|
||||
@@ -393,10 +393,14 @@ internal interface _UniFFILib : Library {
|
||||
): RustBuffer.ByValue
|
||||
fun uniffi_pubkymobile_fn_func_publish(`recordName`: RustBuffer.ByValue,`recordContent`: RustBuffer.ByValue,`secretKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
|
||||
): RustBuffer.ByValue
|
||||
fun uniffi_pubkymobile_fn_func_publish_https(`recordName`: RustBuffer.ByValue,`target`: RustBuffer.ByValue,`secretKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
|
||||
): RustBuffer.ByValue
|
||||
fun uniffi_pubkymobile_fn_func_put(`url`: RustBuffer.ByValue,`content`: RustBuffer.ByValue,
|
||||
): Pointer
|
||||
fun uniffi_pubkymobile_fn_func_resolve(`publicKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
|
||||
): RustBuffer.ByValue
|
||||
fun uniffi_pubkymobile_fn_func_resolve_https(`publicKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
|
||||
): RustBuffer.ByValue
|
||||
fun uniffi_pubkymobile_fn_func_sign_in(`secretKey`: RustBuffer.ByValue,
|
||||
): Pointer
|
||||
fun uniffi_pubkymobile_fn_func_sign_out(`secretKey`: RustBuffer.ByValue,
|
||||
@@ -525,10 +529,14 @@ internal interface _UniFFILib : Library {
|
||||
): Short
|
||||
fun uniffi_pubkymobile_checksum_func_publish(
|
||||
): Short
|
||||
fun uniffi_pubkymobile_checksum_func_publish_https(
|
||||
): Short
|
||||
fun uniffi_pubkymobile_checksum_func_put(
|
||||
): Short
|
||||
fun uniffi_pubkymobile_checksum_func_resolve(
|
||||
): Short
|
||||
fun uniffi_pubkymobile_checksum_func_resolve_https(
|
||||
): Short
|
||||
fun uniffi_pubkymobile_checksum_func_sign_in(
|
||||
): Short
|
||||
fun uniffi_pubkymobile_checksum_func_sign_out(
|
||||
@@ -564,12 +572,18 @@ private fun uniffiCheckApiChecksums(lib: _UniFFILib) {
|
||||
if (lib.uniffi_pubkymobile_checksum_func_publish() != 20156.toShort()) {
|
||||
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
||||
}
|
||||
if (lib.uniffi_pubkymobile_checksum_func_publish_https() != 14705.toShort()) {
|
||||
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
||||
}
|
||||
if (lib.uniffi_pubkymobile_checksum_func_put() != 47594.toShort()) {
|
||||
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
||||
}
|
||||
if (lib.uniffi_pubkymobile_checksum_func_resolve() != 18303.toShort()) {
|
||||
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
||||
}
|
||||
if (lib.uniffi_pubkymobile_checksum_func_resolve_https() != 34593.toShort()) {
|
||||
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
||||
}
|
||||
if (lib.uniffi_pubkymobile_checksum_func_sign_in() != 53969.toShort()) {
|
||||
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
|
||||
}
|
||||
@@ -751,6 +765,14 @@ fun `publish`(`recordName`: String, `recordContent`: String, `secretKey`: String
|
||||
}
|
||||
|
||||
|
||||
fun `publishHttps`(`recordName`: String, `target`: String, `secretKey`: String): List<String> {
|
||||
return FfiConverterSequenceString.lift(
|
||||
rustCall() { _status ->
|
||||
_UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_publish_https(FfiConverterString.lower(`recordName`),FfiConverterString.lower(`target`),FfiConverterString.lower(`secretKey`),_status)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
||||
suspend fun `put`(`url`: String, `content`: String) : List<String> {
|
||||
return uniffiRustCallAsync(
|
||||
@@ -773,6 +795,14 @@ fun `resolve`(`publicKey`: String): List<String> {
|
||||
}
|
||||
|
||||
|
||||
fun `resolveHttps`(`publicKey`: String): List<String> {
|
||||
return FfiConverterSequenceString.lift(
|
||||
rustCall() { _status ->
|
||||
_UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_resolve_https(FfiConverterString.lower(`publicKey`),_status)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
||||
suspend fun `signIn`(`secretKey`: String) : List<String> {
|
||||
return uniffiRustCallAsync(
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1237,7 +1237,7 @@ PODS:
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- react-native-pubky (0.4.0):
|
||||
- react-native-pubky (0.5.0):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
@@ -1757,7 +1757,7 @@ SPEC CHECKSUMS:
|
||||
React-logger: 4072f39df335ca443932e0ccece41fbeb5ca8404
|
||||
React-Mapbuffer: 714f2fae68edcabfc332b754e9fbaa8cfc68fdd4
|
||||
React-microtasksnativemodule: 4943ad8f99be8ccf5a63329fa7d269816609df9e
|
||||
react-native-pubky: d9834542073d368f48e8f0bcce3d7d92317159fa
|
||||
react-native-pubky: 6eb6e656a9c7bfc4310556c142db5861a2fe5b7f
|
||||
React-nativeconfig: 4a9543185905fe41014c06776bf126083795aed9
|
||||
React-NativeModulesApple: 0506da59fc40d2e1e6e12a233db5e81c46face27
|
||||
React-perflogger: 3bbb82f18e9ac29a1a6931568e99d6305ef4403b
|
||||
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
signOut,
|
||||
put,
|
||||
get,
|
||||
resolveHttps,
|
||||
publishHttps,
|
||||
} from '@synonymdev/react-native-pubky';
|
||||
|
||||
export default function App() {
|
||||
@@ -167,6 +169,44 @@ export default function App() {
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
title={'publishHttps'}
|
||||
onPress={async (): Promise<void> => {
|
||||
try {
|
||||
const res = await publishHttps(
|
||||
'example.com', // Record Name
|
||||
'target.example.com', // Target
|
||||
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' // Secret Key
|
||||
);
|
||||
if (res.isErr()) {
|
||||
console.log(res.error.message);
|
||||
return;
|
||||
}
|
||||
console.log(res.value);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
title={'resolveHttps'}
|
||||
onPress={async (): Promise<void> => {
|
||||
try {
|
||||
const res = await resolveHttps(
|
||||
'z4e8s17cou9qmuwen8p1556jzhf1wktmzo6ijsfnri9c4hnrdfty' // Public key
|
||||
);
|
||||
if (res.isErr()) {
|
||||
console.log(res.error.message);
|
||||
return;
|
||||
}
|
||||
console.log(res.value);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,22 +4,6 @@
|
||||
<dict>
|
||||
<key>AvailableLibraries</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>BinaryPath</key>
|
||||
<string>libpubkymobile.a</string>
|
||||
<key>HeadersPath</key>
|
||||
<string>Headers</string>
|
||||
<key>LibraryIdentifier</key>
|
||||
<string>ios-arm64</string>
|
||||
<key>LibraryPath</key>
|
||||
<string>libpubkymobile.a</string>
|
||||
<key>SupportedArchitectures</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>SupportedPlatform</key>
|
||||
<string>ios</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>BinaryPath</key>
|
||||
<string>libpubkymobile.a</string>
|
||||
@@ -38,6 +22,22 @@
|
||||
<key>SupportedPlatformVariant</key>
|
||||
<string>simulator</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>BinaryPath</key>
|
||||
<string>libpubkymobile.a</string>
|
||||
<key>HeadersPath</key>
|
||||
<string>Headers</string>
|
||||
<key>LibraryIdentifier</key>
|
||||
<string>ios-arm64</string>
|
||||
<key>LibraryPath</key>
|
||||
<string>libpubkymobile.a</string>
|
||||
<key>SupportedArchitectures</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>SupportedPlatform</key>
|
||||
<string>ios</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XFWK</string>
|
||||
|
||||
@@ -71,10 +71,14 @@ RustBuffer uniffi_pubkymobile_fn_func_parse_auth_url(RustBuffer url, RustCallSta
|
||||
);
|
||||
RustBuffer uniffi_pubkymobile_fn_func_publish(RustBuffer record_name, RustBuffer record_content, RustBuffer secret_key, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
RustBuffer uniffi_pubkymobile_fn_func_publish_https(RustBuffer record_name, RustBuffer target, RustBuffer secret_key, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
void* _Nonnull uniffi_pubkymobile_fn_func_put(RustBuffer url, RustBuffer content
|
||||
);
|
||||
RustBuffer uniffi_pubkymobile_fn_func_resolve(RustBuffer public_key, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
RustBuffer uniffi_pubkymobile_fn_func_resolve_https(RustBuffer public_key, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
void* _Nonnull uniffi_pubkymobile_fn_func_sign_in(RustBuffer secret_key
|
||||
);
|
||||
void* _Nonnull uniffi_pubkymobile_fn_func_sign_out(RustBuffer secret_key
|
||||
@@ -206,12 +210,18 @@ uint16_t uniffi_pubkymobile_checksum_func_parse_auth_url(void
|
||||
);
|
||||
uint16_t uniffi_pubkymobile_checksum_func_publish(void
|
||||
|
||||
);
|
||||
uint16_t uniffi_pubkymobile_checksum_func_publish_https(void
|
||||
|
||||
);
|
||||
uint16_t uniffi_pubkymobile_checksum_func_put(void
|
||||
|
||||
);
|
||||
uint16_t uniffi_pubkymobile_checksum_func_resolve(void
|
||||
|
||||
);
|
||||
uint16_t uniffi_pubkymobile_checksum_func_resolve_https(void
|
||||
|
||||
);
|
||||
uint16_t uniffi_pubkymobile_checksum_func_sign_in(void
|
||||
|
||||
|
||||
Binary file not shown.
@@ -71,10 +71,14 @@ RustBuffer uniffi_pubkymobile_fn_func_parse_auth_url(RustBuffer url, RustCallSta
|
||||
);
|
||||
RustBuffer uniffi_pubkymobile_fn_func_publish(RustBuffer record_name, RustBuffer record_content, RustBuffer secret_key, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
RustBuffer uniffi_pubkymobile_fn_func_publish_https(RustBuffer record_name, RustBuffer target, RustBuffer secret_key, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
void* _Nonnull uniffi_pubkymobile_fn_func_put(RustBuffer url, RustBuffer content
|
||||
);
|
||||
RustBuffer uniffi_pubkymobile_fn_func_resolve(RustBuffer public_key, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
RustBuffer uniffi_pubkymobile_fn_func_resolve_https(RustBuffer public_key, RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
void* _Nonnull uniffi_pubkymobile_fn_func_sign_in(RustBuffer secret_key
|
||||
);
|
||||
void* _Nonnull uniffi_pubkymobile_fn_func_sign_out(RustBuffer secret_key
|
||||
@@ -206,12 +210,18 @@ uint16_t uniffi_pubkymobile_checksum_func_parse_auth_url(void
|
||||
);
|
||||
uint16_t uniffi_pubkymobile_checksum_func_publish(void
|
||||
|
||||
);
|
||||
uint16_t uniffi_pubkymobile_checksum_func_publish_https(void
|
||||
|
||||
);
|
||||
uint16_t uniffi_pubkymobile_checksum_func_put(void
|
||||
|
||||
);
|
||||
uint16_t uniffi_pubkymobile_checksum_func_resolve(void
|
||||
|
||||
);
|
||||
uint16_t uniffi_pubkymobile_checksum_func_resolve_https(void
|
||||
|
||||
);
|
||||
uint16_t uniffi_pubkymobile_checksum_func_sign_in(void
|
||||
|
||||
|
||||
Binary file not shown.
10
ios/Pubky.mm
10
ios/Pubky.mm
@@ -43,6 +43,16 @@ RCT_EXTERN_METHOD(get:(NSString *)url
|
||||
withResolver:(RCTPromiseResolveBlock)resolve
|
||||
withRejecter:(RCTPromiseRejectBlock)reject)
|
||||
|
||||
RCT_EXTERN_METHOD(publishHttps:(NSString *)recordName
|
||||
target:(NSString *)target
|
||||
secretKey:(NSString *)secretKey
|
||||
withResolver:(RCTPromiseResolveBlock)resolve
|
||||
withRejecter:(RCTPromiseRejectBlock)reject)
|
||||
|
||||
RCT_EXTERN_METHOD(resolveHttps:(NSString *)publicKey
|
||||
withResolver:(RCTPromiseResolveBlock)resolve
|
||||
withRejecter:(RCTPromiseRejectBlock)reject)
|
||||
|
||||
+ (BOOL)requiresMainQueueSetup
|
||||
{
|
||||
return NO;
|
||||
|
||||
@@ -109,4 +109,28 @@ class Pubky: NSObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc(publishHttps:target:secretKey:withResolver:withRejecter:)
|
||||
func publishHttps(_ recordName: String, target: String, secretKey: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||
Task {
|
||||
do {
|
||||
let result = try await react_native_pubky.publishHttps(recordName: recordName, target: target, secretKey: secretKey)
|
||||
resolve(result)
|
||||
} catch {
|
||||
reject("publishHttps Error", "Failed to publish HTTPS record", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc(resolveHttps:withResolver:withRejecter:)
|
||||
func resolveHttps(_ publicKey: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||
Task {
|
||||
do {
|
||||
let result = try await react_native_pubky.resolveHttps(publicKey: publicKey)
|
||||
resolve(result)
|
||||
} catch {
|
||||
reject("resolveHttps Error", "Failed to resolve HTTPS record", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,6 +467,17 @@ public func publish(recordName: String, recordContent: String, secretKey: String
|
||||
)
|
||||
}
|
||||
|
||||
public func publishHttps(recordName: String, target: String, secretKey: String) -> [String] {
|
||||
return try! FfiConverterSequenceString.lift(
|
||||
try! rustCall() {
|
||||
uniffi_pubkymobile_fn_func_publish_https(
|
||||
FfiConverterString.lower(recordName),
|
||||
FfiConverterString.lower(target),
|
||||
FfiConverterString.lower(secretKey),$0)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
public func put(url: String, content: String) async -> [String] {
|
||||
return try! await uniffiRustCallAsync(
|
||||
rustFutureFunc: {
|
||||
@@ -495,6 +506,15 @@ public func resolve(publicKey: String) -> [String] {
|
||||
)
|
||||
}
|
||||
|
||||
public func resolveHttps(publicKey: String) -> [String] {
|
||||
return try! FfiConverterSequenceString.lift(
|
||||
try! rustCall() {
|
||||
uniffi_pubkymobile_fn_func_resolve_https(
|
||||
FfiConverterString.lower(publicKey),$0)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
public func signIn(secretKey: String) async -> [String] {
|
||||
return try! await uniffiRustCallAsync(
|
||||
rustFutureFunc: {
|
||||
@@ -577,12 +597,18 @@ private var initializationResult: InitializationResult {
|
||||
if (uniffi_pubkymobile_checksum_func_publish() != 20156) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_pubkymobile_checksum_func_publish_https() != 14705) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_pubkymobile_checksum_func_put() != 47594) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_pubkymobile_checksum_func_resolve() != 18303) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_pubkymobile_checksum_func_resolve_https() != 34593) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
if (uniffi_pubkymobile_checksum_func_sign_in() != 53969) {
|
||||
return InitializationResult.apiChecksumMismatch
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@synonymdev/react-native-pubky",
|
||||
"version": "0.4.0",
|
||||
"version": "0.5.0",
|
||||
"description": "React Native Implementation of Pubky",
|
||||
"source": "./src/index.tsx",
|
||||
"main": "./lib/commonjs/index.js",
|
||||
|
||||
3
rust/Cargo.lock
generated
3
rust/Cargo.lock
generated
@@ -1822,8 +1822,9 @@ dependencies = [
|
||||
name = "react_native_pubky"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"base64 0.22.1",
|
||||
"hex",
|
||||
"once_cell",
|
||||
"pkarr",
|
||||
"pubky",
|
||||
"pubky-common",
|
||||
|
||||
@@ -23,4 +23,5 @@ pkarr = { git = "https://github.com/Pubky/pkarr", branch = "v3", features = ["as
|
||||
pubky = { version = "0.1.0", path = "pubky/pubky" }
|
||||
pubky-common = { version = "0.1.0", path = "pubky/pubky-common" }
|
||||
pubky_homeserver = { version = "0.1.0", path = "pubky/pubky-homeserver" }
|
||||
base64 = "0.21.7"
|
||||
base64 = "0.22.1"
|
||||
once_cell = "1.19.0"
|
||||
|
||||
201
rust/src/lib.rs
201
rust/src/lib.rs
@@ -15,18 +15,168 @@ use base64::Engine;
|
||||
use base64::engine::general_purpose;
|
||||
use pubky::PubkyClient;
|
||||
use hex;
|
||||
use hex::ToHex;
|
||||
use serde::Serialize;
|
||||
use url::Url;
|
||||
use tokio;
|
||||
use pkarr::{PkarrClient, SignedPacket, Keypair, dns, PublicKey};
|
||||
use pkarr::dns::rdata::RData;
|
||||
use pkarr::dns::ResourceRecord;
|
||||
use pkarr::dns::rdata::{RData, HTTPS, SVCB};
|
||||
use pkarr::dns::{Packet, ResourceRecord};
|
||||
use serde_json::json;
|
||||
use utils::*;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::sync::Arc;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
static PKARR_CLIENT: Lazy<Arc<PkarrClient>> = Lazy::new(|| {
|
||||
Arc::new(
|
||||
PkarrClient::builder()
|
||||
.build()
|
||||
.expect("Failed to build PkarrClient"),
|
||||
)
|
||||
});
|
||||
|
||||
static PUBKY_CLIENT: Lazy<Arc<PubkyClient>> = Lazy::new(|| {
|
||||
Arc::new(PubkyClient::testnet())
|
||||
});
|
||||
|
||||
static TOKIO_RUNTIME: Lazy<Arc<Runtime>> = Lazy::new(|| {
|
||||
Arc::new(
|
||||
Runtime::new().expect("Failed to create Tokio runtime")
|
||||
)
|
||||
});
|
||||
|
||||
#[uniffi::export]
|
||||
pub fn publish_https(record_name: String, target: String, secret_key: String) -> Vec<String> {
|
||||
let client = PKARR_CLIENT.clone();
|
||||
|
||||
let keypair = match get_keypair_from_secret_key(&secret_key) {
|
||||
Ok(keypair) => keypair,
|
||||
Err(error) => return create_response_vector(true, error),
|
||||
};
|
||||
|
||||
// Create SVCB record with the target domain
|
||||
let target = match target.as_str().try_into() {
|
||||
Ok(target) => target,
|
||||
Err(e) => return create_response_vector(true, format!("Invalid target: {}", e)),
|
||||
};
|
||||
let svcb = SVCB::new(0, target);
|
||||
|
||||
// Create HTTPS record
|
||||
let https_record = HTTPS(svcb);
|
||||
|
||||
// Create DNS packet
|
||||
let mut packet = Packet::new_reply(0);
|
||||
let dns_name = match dns::Name::new(&record_name) {
|
||||
Ok(name) => name,
|
||||
Err(e) => return create_response_vector(true, format!("Invalid DNS name: {}", e)),
|
||||
};
|
||||
|
||||
packet.answers.push(ResourceRecord::new(
|
||||
dns_name,
|
||||
dns::CLASS::IN,
|
||||
3600, // TTL in seconds
|
||||
dns::rdata::RData::HTTPS(https_record),
|
||||
));
|
||||
|
||||
let signed_packet = match SignedPacket::from_packet(&keypair, &packet) {
|
||||
Ok(signed_packet) => signed_packet,
|
||||
Err(e) => return create_response_vector(true, format!("Failed to create signed packet: {}", e)),
|
||||
};
|
||||
|
||||
match client.publish(&signed_packet) {
|
||||
Ok(()) => create_response_vector(false, keypair.public_key().to_string()),
|
||||
Err(e) => create_response_vector(true, format!("Failed to publish: {}", e)),
|
||||
}
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
pub fn resolve_https(public_key: String) -> Vec<String> {
|
||||
let public_key = match public_key.as_str().try_into() {
|
||||
Ok(key) => key,
|
||||
Err(e) => return create_response_vector(true, format!("Invalid public key: {}", e)),
|
||||
};
|
||||
|
||||
let client = PKARR_CLIENT.clone();
|
||||
|
||||
match client.resolve(&public_key) {
|
||||
Ok(Some(signed_packet)) => {
|
||||
// Extract HTTPS records from the signed packet
|
||||
let https_records: Vec<serde_json::Value> = signed_packet.packet().answers.iter()
|
||||
.filter_map(|record| {
|
||||
if let dns::rdata::RData::HTTPS(https) = &record.rdata {
|
||||
// Create a JSON object
|
||||
let mut https_json = serde_json::json!({
|
||||
"name": record.name.to_string(),
|
||||
"class": format!("{:?}", record.class),
|
||||
"ttl": record.ttl,
|
||||
"priority": https.0.priority,
|
||||
"target": https.0.target.to_string(),
|
||||
});
|
||||
|
||||
// Access specific parameters using the constants from SVCB
|
||||
if let Some(port_param) = https.0.get_param(SVCB::PORT) {
|
||||
if port_param.len() == 2 {
|
||||
let port = u16::from_be_bytes([port_param[0], port_param[1]]);
|
||||
https_json["port"] = serde_json::json!(port);
|
||||
}
|
||||
}
|
||||
|
||||
// Access ALPN parameter if needed
|
||||
if let Some(alpn_param) = https.0.get_param(SVCB::ALPN) {
|
||||
// Parse ALPN protocols (list of character strings)
|
||||
let mut position = 0;
|
||||
let mut alpn_protocols = Vec::new();
|
||||
while position < alpn_param.len() {
|
||||
let length = alpn_param[position] as usize;
|
||||
position += 1;
|
||||
if position + length <= alpn_param.len() {
|
||||
let protocol = String::from_utf8_lossy(
|
||||
&alpn_param[position..position + length],
|
||||
);
|
||||
alpn_protocols.push(protocol.to_string());
|
||||
position += length;
|
||||
} else {
|
||||
break; // Malformed ALPN parameter
|
||||
}
|
||||
}
|
||||
https_json["alpn"] = serde_json::json!(alpn_protocols);
|
||||
}
|
||||
// TODO: Add other parameters as needed.
|
||||
Some(https_json)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
if https_records.is_empty() {
|
||||
return create_response_vector(true, "No HTTPS records found".to_string());
|
||||
}
|
||||
|
||||
// Create JSON response
|
||||
let json_obj = json!({
|
||||
"public_key": public_key.to_string(),
|
||||
"https_records": https_records,
|
||||
"last_seen": signed_packet.last_seen(),
|
||||
"timestamp": signed_packet.timestamp(),
|
||||
});
|
||||
|
||||
let json_str = match serde_json::to_string(&json_obj) {
|
||||
Ok(json) => json,
|
||||
Err(e) => return create_response_vector(true, format!("Failed to serialize JSON: {}", e)),
|
||||
};
|
||||
|
||||
create_response_vector(false, json_str)
|
||||
},
|
||||
Ok(None) => create_response_vector(true, "No signed packet found".to_string()),
|
||||
Err(e) => create_response_vector(true, format!("Failed to resolve: {}", e)),
|
||||
}
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
pub async fn sign_up(secret_key: String, homeserver: String) -> Vec<String> {
|
||||
let client = PubkyClient::testnet();
|
||||
let client = PUBKY_CLIENT.clone();
|
||||
let keypair = match get_keypair_from_secret_key(&secret_key) {
|
||||
Ok(keypair) => keypair,
|
||||
Err(error) => return create_response_vector(true, error),
|
||||
@@ -45,7 +195,7 @@ pub async fn sign_up(secret_key: String, homeserver: String) -> Vec<String> {
|
||||
|
||||
#[uniffi::export]
|
||||
pub async fn sign_in(secret_key: String) -> Vec<String> {
|
||||
let client = PubkyClient::testnet();
|
||||
let client = PUBKY_CLIENT.clone();
|
||||
let keypair = match get_keypair_from_secret_key(&secret_key) {
|
||||
Ok(keypair) => keypair,
|
||||
Err(error) => return create_response_vector(true, error),
|
||||
@@ -60,7 +210,7 @@ pub async fn sign_in(secret_key: String) -> Vec<String> {
|
||||
|
||||
#[uniffi::export]
|
||||
pub async fn sign_out(secret_key: String) -> Vec<String> {
|
||||
let client = PubkyClient::testnet();
|
||||
let client = PUBKY_CLIENT.clone();
|
||||
let keypair = match get_keypair_from_secret_key(&secret_key) {
|
||||
Ok(keypair) => keypair,
|
||||
Err(error) => return create_response_vector(true, error),
|
||||
@@ -75,7 +225,7 @@ pub async fn sign_out(secret_key: String) -> Vec<String> {
|
||||
|
||||
#[uniffi::export]
|
||||
pub async fn put(url: String, content: String) -> Vec<String> {
|
||||
let client = PubkyClient::testnet();
|
||||
let client = PUBKY_CLIENT.clone();
|
||||
let parsed_url = match Url::parse(&url) {
|
||||
Ok(url) => url,
|
||||
Err(_) => return create_response_vector(true, "Failed to parse URL".to_string()),
|
||||
@@ -90,7 +240,7 @@ pub async fn put(url: String, content: String) -> Vec<String> {
|
||||
|
||||
#[uniffi::export]
|
||||
pub async fn get(url: String) -> Vec<String> {
|
||||
let client = PubkyClient::testnet();
|
||||
let client = PUBKY_CLIENT.clone();
|
||||
let parsed_url = match Url::parse(&url) {
|
||||
Ok(url) => url,
|
||||
Err(_) => return create_response_vector(true, "Failed to parse URL".to_string()),
|
||||
@@ -103,16 +253,19 @@ pub async fn get(url: String) -> Vec<String> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a signed packet from a public key
|
||||
* @param public_key The public key to resolve
|
||||
* @returns A vector with two elements: the first element is a boolean indicating success or failure,
|
||||
* and the second element is the response data (either an error message or the resolved signed packet)
|
||||
**/
|
||||
#[uniffi::export]
|
||||
fn resolve(public_key: String) -> Vec<String> {
|
||||
pub fn resolve(public_key: String) -> Vec<String> {
|
||||
let public_key = match public_key.as_str().try_into() {
|
||||
Ok(key) => key,
|
||||
Err(e) => return create_response_vector(true, format!("Invalid zbase32 encoded key: {}", e)),
|
||||
};
|
||||
let client = match PkarrClient::builder().build() {
|
||||
Ok(client) => client,
|
||||
Err(e) => return create_response_vector(true, format!("Failed to build PkarrClient: {}", e)),
|
||||
};
|
||||
let client = PKARR_CLIENT.clone();
|
||||
|
||||
match client.resolve(&public_key) {
|
||||
Ok(Some(signed_packet)) => {
|
||||
@@ -135,16 +288,16 @@ fn resolve(public_key: String) -> Vec<String> {
|
||||
let bytes = signed_packet.as_bytes();
|
||||
let public_key = &bytes[..32];
|
||||
let signature = &bytes[32..96];
|
||||
let timestamp = u64::from_be_bytes(match bytes[96..104].try_into() {
|
||||
Ok(tsbytes) => tsbytes,
|
||||
Err(_) => return create_response_vector(true, "Failed to convert timestamp bytes".to_string())
|
||||
});
|
||||
let timestamp = signed_packet.timestamp();
|
||||
let dns_packet = &bytes[104..];
|
||||
let hex: String = signed_packet.encode_hex();
|
||||
|
||||
let json_obj = json!({
|
||||
"signed_packet": hex,
|
||||
"public_key": general_purpose::STANDARD.encode(public_key),
|
||||
"signature": general_purpose::STANDARD.encode(signature),
|
||||
"timestamp": timestamp,
|
||||
"last_seen": signed_packet.last_seen(),
|
||||
"dns_packet": general_purpose::STANDARD.encode(dns_packet),
|
||||
"records": json_records
|
||||
});
|
||||
@@ -164,11 +317,8 @@ fn resolve(public_key: String) -> Vec<String> {
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
fn publish(record_name: String, record_content: String, secret_key: String) -> Vec<String> {
|
||||
let client = match PkarrClient::builder().build() {
|
||||
Ok(client) => client,
|
||||
Err(e) => return create_response_vector(true, format!("Failed to build PkarrClient: {}", e)),
|
||||
};
|
||||
pub fn publish(record_name: String, record_content: String, secret_key: String) -> Vec<String> {
|
||||
let client = PKARR_CLIENT.clone();
|
||||
|
||||
let keypair = match get_keypair_from_secret_key(&secret_key) {
|
||||
Ok(keypair) => keypair,
|
||||
@@ -215,15 +365,14 @@ fn publish(record_name: String, record_content: String, secret_key: String) -> V
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[uniffi::export]
|
||||
fn auth(url: String, secret_key: String) -> Vec<String> {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(authorize(url, secret_key))
|
||||
pub fn auth(url: String, secret_key: String) -> Vec<String> {
|
||||
let runtime = TOKIO_RUNTIME.clone();
|
||||
runtime.block_on(authorize(url, secret_key))
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
fn parse_auth_url(url: String) -> Vec<String> {
|
||||
pub fn parse_auth_url(url: String) -> Vec<String> {
|
||||
let parsed_details = match parse_pubky_auth_url(&url) {
|
||||
Ok(details) => details,
|
||||
Err(error) => return create_response_vector(true, error),
|
||||
|
||||
@@ -82,11 +82,13 @@ interface ITxt {
|
||||
ttl: number;
|
||||
}
|
||||
interface IDNSPacket {
|
||||
dns_packet: string;
|
||||
signed_packet: string;
|
||||
public_key: string;
|
||||
records: ITxt[];
|
||||
signature: string;
|
||||
timestamp: number;
|
||||
last_seen: number;
|
||||
dns_packet: string;
|
||||
records: ITxt[];
|
||||
}
|
||||
export async function resolve(publicKey: string): Promise<Result<IDNSPacket>> {
|
||||
try {
|
||||
@@ -165,3 +167,48 @@ export async function put(
|
||||
return err(JSON.stringify(e));
|
||||
}
|
||||
}
|
||||
|
||||
export async function publishHttps(
|
||||
recordName: string,
|
||||
target: string,
|
||||
secretKey: string
|
||||
): Promise<Result<string[]>> {
|
||||
try {
|
||||
const res = await Pubky.publishHttps(recordName, target, secretKey);
|
||||
if (res[0] === 'error') {
|
||||
return err(res[1]);
|
||||
}
|
||||
return ok(res[1]);
|
||||
} catch (e) {
|
||||
return err(JSON.stringify(e));
|
||||
}
|
||||
}
|
||||
|
||||
interface IHttpsRecord {
|
||||
name: string;
|
||||
class: string;
|
||||
ttl: number;
|
||||
priority: number;
|
||||
target: string;
|
||||
port?: number;
|
||||
alpn?: string[];
|
||||
}
|
||||
|
||||
interface IHttpsResolveResult {
|
||||
public_key: string;
|
||||
https_records: IHttpsRecord[];
|
||||
}
|
||||
|
||||
export async function resolveHttps(
|
||||
publicKey: string
|
||||
): Promise<Result<IHttpsResolveResult>> {
|
||||
try {
|
||||
const res = await Pubky.resolveHttps(publicKey);
|
||||
if (res[0] === 'error') {
|
||||
return err(res[1]);
|
||||
}
|
||||
return ok(JSON.parse(res[1]));
|
||||
} catch (e) {
|
||||
return err(JSON.stringify(e));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user