Merge pull request #10 from pubky/publish-resolve-https

feat: add publish_https & resolve_https
This commit is contained in:
Corey
2024-09-27 10:49:22 -04:00
committed by GitHub
22 changed files with 469 additions and 49 deletions

View File

@@ -14,6 +14,8 @@ npm install @synonymdev/react-native-pubky
- [x] [parseAuthUrl](#parseAuthUrl): Method to decode an authUrl. - [x] [parseAuthUrl](#parseAuthUrl): Method to decode an authUrl.
- [x] [publish](#publish): Functionality to publish content. - [x] [publish](#publish): Functionality to publish content.
- [x] [resolve](#resolve): Functionality to resolve content. - [x] [resolve](#resolve): Functionality to resolve content.
- [x] [publishHttps](#publishHttps): Publish HTTPS records.
- [x] [resolveHttps](#resolveHttps): Resolve HTTPS records.
### Methods to be Implemented ### Methods to be Implemented
- [ ] signIn: Sign-in to a homeserver. - [ ] signIn: Sign-in to a homeserver.
- [ ] signUp: Sign-up to a homeserver and update Pkarr accordingly. - [ ] signUp: Sign-up to a homeserver and update Pkarr accordingly.
@@ -78,6 +80,36 @@ if (resolveRes.isErr()) {
console.log(resolveRes.value); 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 ## Local Installation
1. Clone & npm install: 1. Clone & npm install:

View File

@@ -18,6 +18,8 @@ import uniffi.pubkymobile.signIn
import uniffi.pubkymobile.signOut import uniffi.pubkymobile.signOut
import uniffi.pubkymobile.put import uniffi.pubkymobile.put
import uniffi.pubkymobile.get import uniffi.pubkymobile.get
import uniffi.pubkymobile.publishHttps
import uniffi.pubkymobile.resolveHttps
class PubkyModule(reactContext: ReactApplicationContext) : class PubkyModule(reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) { 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 { companion object {
const val NAME = "Pubky" const val NAME = "Pubky"
} }

View File

@@ -393,10 +393,14 @@ internal interface _UniFFILib : Library {
): RustBuffer.ByValue ): RustBuffer.ByValue
fun uniffi_pubkymobile_fn_func_publish(`recordName`: RustBuffer.ByValue,`recordContent`: RustBuffer.ByValue,`secretKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus, fun uniffi_pubkymobile_fn_func_publish(`recordName`: RustBuffer.ByValue,`recordContent`: RustBuffer.ByValue,`secretKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
): RustBuffer.ByValue ): 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, fun uniffi_pubkymobile_fn_func_put(`url`: RustBuffer.ByValue,`content`: RustBuffer.ByValue,
): Pointer ): Pointer
fun uniffi_pubkymobile_fn_func_resolve(`publicKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus, fun uniffi_pubkymobile_fn_func_resolve(`publicKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
): RustBuffer.ByValue ): 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, fun uniffi_pubkymobile_fn_func_sign_in(`secretKey`: RustBuffer.ByValue,
): Pointer ): Pointer
fun uniffi_pubkymobile_fn_func_sign_out(`secretKey`: RustBuffer.ByValue, fun uniffi_pubkymobile_fn_func_sign_out(`secretKey`: RustBuffer.ByValue,
@@ -525,10 +529,14 @@ internal interface _UniFFILib : Library {
): Short ): Short
fun uniffi_pubkymobile_checksum_func_publish( fun uniffi_pubkymobile_checksum_func_publish(
): Short ): Short
fun uniffi_pubkymobile_checksum_func_publish_https(
): Short
fun uniffi_pubkymobile_checksum_func_put( fun uniffi_pubkymobile_checksum_func_put(
): Short ): Short
fun uniffi_pubkymobile_checksum_func_resolve( fun uniffi_pubkymobile_checksum_func_resolve(
): Short ): Short
fun uniffi_pubkymobile_checksum_func_resolve_https(
): Short
fun uniffi_pubkymobile_checksum_func_sign_in( fun uniffi_pubkymobile_checksum_func_sign_in(
): Short ): Short
fun uniffi_pubkymobile_checksum_func_sign_out( 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()) { if (lib.uniffi_pubkymobile_checksum_func_publish() != 20156.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") 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()) { if (lib.uniffi_pubkymobile_checksum_func_put() != 47594.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
} }
if (lib.uniffi_pubkymobile_checksum_func_resolve() != 18303.toShort()) { if (lib.uniffi_pubkymobile_checksum_func_resolve() != 18303.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") 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()) { if (lib.uniffi_pubkymobile_checksum_func_sign_in() != 53969.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") 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") @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
suspend fun `put`(`url`: String, `content`: String) : List<String> { suspend fun `put`(`url`: String, `content`: String) : List<String> {
return uniffiRustCallAsync( 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") @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
suspend fun `signIn`(`secretKey`: String) : List<String> { suspend fun `signIn`(`secretKey`: String) : List<String> {
return uniffiRustCallAsync( return uniffiRustCallAsync(

View File

@@ -1237,7 +1237,7 @@ PODS:
- ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core - ReactCommon/turbomodule/core
- Yoga - Yoga
- react-native-pubky (0.4.0): - react-native-pubky (0.5.0):
- DoubleConversion - DoubleConversion
- glog - glog
- hermes-engine - hermes-engine
@@ -1757,7 +1757,7 @@ SPEC CHECKSUMS:
React-logger: 4072f39df335ca443932e0ccece41fbeb5ca8404 React-logger: 4072f39df335ca443932e0ccece41fbeb5ca8404
React-Mapbuffer: 714f2fae68edcabfc332b754e9fbaa8cfc68fdd4 React-Mapbuffer: 714f2fae68edcabfc332b754e9fbaa8cfc68fdd4
React-microtasksnativemodule: 4943ad8f99be8ccf5a63329fa7d269816609df9e React-microtasksnativemodule: 4943ad8f99be8ccf5a63329fa7d269816609df9e
react-native-pubky: d9834542073d368f48e8f0bcce3d7d92317159fa react-native-pubky: 6eb6e656a9c7bfc4310556c142db5861a2fe5b7f
React-nativeconfig: 4a9543185905fe41014c06776bf126083795aed9 React-nativeconfig: 4a9543185905fe41014c06776bf126083795aed9
React-NativeModulesApple: 0506da59fc40d2e1e6e12a233db5e81c46face27 React-NativeModulesApple: 0506da59fc40d2e1e6e12a233db5e81c46face27
React-perflogger: 3bbb82f18e9ac29a1a6931568e99d6305ef4403b React-perflogger: 3bbb82f18e9ac29a1a6931568e99d6305ef4403b

View File

@@ -9,6 +9,8 @@ import {
signOut, signOut,
put, put,
get, get,
resolveHttps,
publishHttps,
} from '@synonymdev/react-native-pubky'; } from '@synonymdev/react-native-pubky';
export default function App() { 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> </View>
); );
} }

View File

@@ -4,22 +4,6 @@
<dict> <dict>
<key>AvailableLibraries</key> <key>AvailableLibraries</key>
<array> <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> <dict>
<key>BinaryPath</key> <key>BinaryPath</key>
<string>libpubkymobile.a</string> <string>libpubkymobile.a</string>
@@ -38,6 +22,22 @@
<key>SupportedPlatformVariant</key> <key>SupportedPlatformVariant</key>
<string>simulator</string> <string>simulator</string>
</dict> </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> </array>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>XFWK</string> <string>XFWK</string>

View File

@@ -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(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 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(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_in(RustBuffer secret_key
); );
void* _Nonnull uniffi_pubkymobile_fn_func_sign_out(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(void
);
uint16_t uniffi_pubkymobile_checksum_func_publish_https(void
); );
uint16_t uniffi_pubkymobile_checksum_func_put(void uint16_t uniffi_pubkymobile_checksum_func_put(void
); );
uint16_t uniffi_pubkymobile_checksum_func_resolve(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 uint16_t uniffi_pubkymobile_checksum_func_sign_in(void

View File

@@ -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(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 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(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_in(RustBuffer secret_key
); );
void* _Nonnull uniffi_pubkymobile_fn_func_sign_out(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(void
);
uint16_t uniffi_pubkymobile_checksum_func_publish_https(void
); );
uint16_t uniffi_pubkymobile_checksum_func_put(void uint16_t uniffi_pubkymobile_checksum_func_put(void
); );
uint16_t uniffi_pubkymobile_checksum_func_resolve(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 uint16_t uniffi_pubkymobile_checksum_func_sign_in(void

View File

@@ -43,6 +43,16 @@ RCT_EXTERN_METHOD(get:(NSString *)url
withResolver:(RCTPromiseResolveBlock)resolve withResolver:(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject) 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 + (BOOL)requiresMainQueueSetup
{ {
return NO; return NO;

View File

@@ -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)
}
}
}
} }

View File

@@ -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] { public func put(url: String, content: String) async -> [String] {
return try! await uniffiRustCallAsync( return try! await uniffiRustCallAsync(
rustFutureFunc: { 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] { public func signIn(secretKey: String) async -> [String] {
return try! await uniffiRustCallAsync( return try! await uniffiRustCallAsync(
rustFutureFunc: { rustFutureFunc: {
@@ -577,12 +597,18 @@ private var initializationResult: InitializationResult {
if (uniffi_pubkymobile_checksum_func_publish() != 20156) { if (uniffi_pubkymobile_checksum_func_publish() != 20156) {
return InitializationResult.apiChecksumMismatch return InitializationResult.apiChecksumMismatch
} }
if (uniffi_pubkymobile_checksum_func_publish_https() != 14705) {
return InitializationResult.apiChecksumMismatch
}
if (uniffi_pubkymobile_checksum_func_put() != 47594) { if (uniffi_pubkymobile_checksum_func_put() != 47594) {
return InitializationResult.apiChecksumMismatch return InitializationResult.apiChecksumMismatch
} }
if (uniffi_pubkymobile_checksum_func_resolve() != 18303) { if (uniffi_pubkymobile_checksum_func_resolve() != 18303) {
return InitializationResult.apiChecksumMismatch return InitializationResult.apiChecksumMismatch
} }
if (uniffi_pubkymobile_checksum_func_resolve_https() != 34593) {
return InitializationResult.apiChecksumMismatch
}
if (uniffi_pubkymobile_checksum_func_sign_in() != 53969) { if (uniffi_pubkymobile_checksum_func_sign_in() != 53969) {
return InitializationResult.apiChecksumMismatch return InitializationResult.apiChecksumMismatch
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@synonymdev/react-native-pubky", "name": "@synonymdev/react-native-pubky",
"version": "0.4.0", "version": "0.5.0",
"description": "React Native Implementation of Pubky", "description": "React Native Implementation of Pubky",
"source": "./src/index.tsx", "source": "./src/index.tsx",
"main": "./lib/commonjs/index.js", "main": "./lib/commonjs/index.js",

3
rust/Cargo.lock generated
View File

@@ -1822,8 +1822,9 @@ dependencies = [
name = "react_native_pubky" name = "react_native_pubky"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"base64 0.21.7", "base64 0.22.1",
"hex", "hex",
"once_cell",
"pkarr", "pkarr",
"pubky", "pubky",
"pubky-common", "pubky-common",

View File

@@ -23,4 +23,5 @@ pkarr = { git = "https://github.com/Pubky/pkarr", branch = "v3", features = ["as
pubky = { version = "0.1.0", path = "pubky/pubky" } pubky = { version = "0.1.0", path = "pubky/pubky" }
pubky-common = { version = "0.1.0", path = "pubky/pubky-common" } pubky-common = { version = "0.1.0", path = "pubky/pubky-common" }
pubky_homeserver = { version = "0.1.0", path = "pubky/pubky-homeserver" } pubky_homeserver = { version = "0.1.0", path = "pubky/pubky-homeserver" }
base64 = "0.21.7" base64 = "0.22.1"
once_cell = "1.19.0"

View File

@@ -15,18 +15,168 @@ use base64::Engine;
use base64::engine::general_purpose; use base64::engine::general_purpose;
use pubky::PubkyClient; use pubky::PubkyClient;
use hex; use hex;
use hex::ToHex;
use serde::Serialize; use serde::Serialize;
use url::Url; use url::Url;
use tokio; use tokio;
use pkarr::{PkarrClient, SignedPacket, Keypair, dns, PublicKey}; use pkarr::{PkarrClient, SignedPacket, Keypair, dns, PublicKey};
use pkarr::dns::rdata::RData; use pkarr::dns::rdata::{RData, HTTPS, SVCB};
use pkarr::dns::ResourceRecord; use pkarr::dns::{Packet, ResourceRecord};
use serde_json::json; use serde_json::json;
use utils::*; 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] #[uniffi::export]
pub async fn sign_up(secret_key: String, homeserver: String) -> Vec<String> { 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) { let keypair = match get_keypair_from_secret_key(&secret_key) {
Ok(keypair) => keypair, Ok(keypair) => keypair,
Err(error) => return create_response_vector(true, error), 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] #[uniffi::export]
pub async fn sign_in(secret_key: String) -> Vec<String> { 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) { let keypair = match get_keypair_from_secret_key(&secret_key) {
Ok(keypair) => keypair, Ok(keypair) => keypair,
Err(error) => return create_response_vector(true, error), Err(error) => return create_response_vector(true, error),
@@ -60,7 +210,7 @@ pub async fn sign_in(secret_key: String) -> Vec<String> {
#[uniffi::export] #[uniffi::export]
pub async fn sign_out(secret_key: String) -> Vec<String> { 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) { let keypair = match get_keypair_from_secret_key(&secret_key) {
Ok(keypair) => keypair, Ok(keypair) => keypair,
Err(error) => return create_response_vector(true, error), Err(error) => return create_response_vector(true, error),
@@ -75,7 +225,7 @@ pub async fn sign_out(secret_key: String) -> Vec<String> {
#[uniffi::export] #[uniffi::export]
pub async fn put(url: String, content: String) -> Vec<String> { 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) { let parsed_url = match Url::parse(&url) {
Ok(url) => url, Ok(url) => url,
Err(_) => return create_response_vector(true, "Failed to parse URL".to_string()), 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] #[uniffi::export]
pub async fn get(url: String) -> Vec<String> { pub async fn get(url: String) -> Vec<String> {
let client = PubkyClient::testnet(); let client = PUBKY_CLIENT.clone();
let parsed_url = match Url::parse(&url) { let parsed_url = match Url::parse(&url) {
Ok(url) => url, Ok(url) => url,
Err(_) => return create_response_vector(true, "Failed to parse URL".to_string()), 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] #[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() { let public_key = match public_key.as_str().try_into() {
Ok(key) => key, Ok(key) => key,
Err(e) => return create_response_vector(true, format!("Invalid zbase32 encoded key: {}", e)), Err(e) => return create_response_vector(true, format!("Invalid zbase32 encoded key: {}", e)),
}; };
let client = match PkarrClient::builder().build() { let client = PKARR_CLIENT.clone();
Ok(client) => client,
Err(e) => return create_response_vector(true, format!("Failed to build PkarrClient: {}", e)),
};
match client.resolve(&public_key) { match client.resolve(&public_key) {
Ok(Some(signed_packet)) => { Ok(Some(signed_packet)) => {
@@ -135,16 +288,16 @@ fn resolve(public_key: String) -> Vec<String> {
let bytes = signed_packet.as_bytes(); let bytes = signed_packet.as_bytes();
let public_key = &bytes[..32]; let public_key = &bytes[..32];
let signature = &bytes[32..96]; let signature = &bytes[32..96];
let timestamp = u64::from_be_bytes(match bytes[96..104].try_into() { let timestamp = signed_packet.timestamp();
Ok(tsbytes) => tsbytes,
Err(_) => return create_response_vector(true, "Failed to convert timestamp bytes".to_string())
});
let dns_packet = &bytes[104..]; let dns_packet = &bytes[104..];
let hex: String = signed_packet.encode_hex();
let json_obj = json!({ let json_obj = json!({
"signed_packet": hex,
"public_key": general_purpose::STANDARD.encode(public_key), "public_key": general_purpose::STANDARD.encode(public_key),
"signature": general_purpose::STANDARD.encode(signature), "signature": general_purpose::STANDARD.encode(signature),
"timestamp": timestamp, "timestamp": timestamp,
"last_seen": signed_packet.last_seen(),
"dns_packet": general_purpose::STANDARD.encode(dns_packet), "dns_packet": general_purpose::STANDARD.encode(dns_packet),
"records": json_records "records": json_records
}); });
@@ -164,11 +317,8 @@ fn resolve(public_key: String) -> Vec<String> {
} }
#[uniffi::export] #[uniffi::export]
fn publish(record_name: String, record_content: String, secret_key: String) -> Vec<String> { pub fn publish(record_name: String, record_content: String, secret_key: String) -> Vec<String> {
let client = match PkarrClient::builder().build() { let client = PKARR_CLIENT.clone();
Ok(client) => client,
Err(e) => return create_response_vector(true, format!("Failed to build PkarrClient: {}", e)),
};
let keypair = match get_keypair_from_secret_key(&secret_key) { let keypair = match get_keypair_from_secret_key(&secret_key) {
Ok(keypair) => keypair, Ok(keypair) => keypair,
@@ -215,15 +365,14 @@ fn publish(record_name: String, record_content: String, secret_key: String) -> V
} }
} }
#[uniffi::export] #[uniffi::export]
fn auth(url: String, secret_key: String) -> Vec<String> { pub fn auth(url: String, secret_key: String) -> Vec<String> {
let rt = tokio::runtime::Runtime::new().unwrap(); let runtime = TOKIO_RUNTIME.clone();
rt.block_on(authorize(url, secret_key)) runtime.block_on(authorize(url, secret_key))
} }
#[uniffi::export] #[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) { let parsed_details = match parse_pubky_auth_url(&url) {
Ok(details) => details, Ok(details) => details,
Err(error) => return create_response_vector(true, error), Err(error) => return create_response_vector(true, error),

View File

@@ -82,11 +82,13 @@ interface ITxt {
ttl: number; ttl: number;
} }
interface IDNSPacket { interface IDNSPacket {
dns_packet: string; signed_packet: string;
public_key: string; public_key: string;
records: ITxt[];
signature: string; signature: string;
timestamp: number; timestamp: number;
last_seen: number;
dns_packet: string;
records: ITxt[];
} }
export async function resolve(publicKey: string): Promise<Result<IDNSPacket>> { export async function resolve(publicKey: string): Promise<Result<IDNSPacket>> {
try { try {
@@ -165,3 +167,48 @@ export async function put(
return err(JSON.stringify(e)); 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));
}
}