mirror of
https://github.com/aljazceru/react-native-pubky.git
synced 2025-12-17 14:44:26 +01:00
fix: add publish and resolve
Adds publish & resolve methods. Updates example app. Add npmignore. Bumps version to 0.3.0.
This commit is contained in:
2
.npmignore
Normal file
2
.npmignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
example/
|
||||||
|
rust/
|
||||||
@@ -11,6 +11,8 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import uniffi.pubkymobile.auth
|
import uniffi.pubkymobile.auth
|
||||||
import uniffi.pubkymobile.parseAuthUrl
|
import uniffi.pubkymobile.parseAuthUrl
|
||||||
|
import uniffi.pubkymobile.publish
|
||||||
|
import uniffi.pubkymobile.resolve
|
||||||
|
|
||||||
class PubkyModule(reactContext: ReactApplicationContext) :
|
class PubkyModule(reactContext: ReactApplicationContext) :
|
||||||
ReactContextBaseJavaModule(reactContext) {
|
ReactContextBaseJavaModule(reactContext) {
|
||||||
@@ -51,6 +53,44 @@ class PubkyModule(reactContext: ReactApplicationContext) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
fun publish(recordName: String, recordContent: String, secretKey: String, promise: Promise) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
try {
|
||||||
|
val result = publish(recordName, recordContent, 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 resolve(publicKey: String, promise: Promise) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
try {
|
||||||
|
val result = resolve(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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -385,6 +385,10 @@ internal interface _UniFFILib : Library {
|
|||||||
): RustBuffer.ByValue
|
): RustBuffer.ByValue
|
||||||
fun uniffi_pubkymobile_fn_func_parse_auth_url(`url`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
|
fun uniffi_pubkymobile_fn_func_parse_auth_url(`url`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
|
||||||
): RustBuffer.ByValue
|
): 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_resolve(`publicKey`: RustBuffer.ByValue,_uniffi_out_err: RustCallStatus,
|
||||||
|
): RustBuffer.ByValue
|
||||||
fun ffi_pubkymobile_rustbuffer_alloc(`size`: Int,_uniffi_out_err: RustCallStatus,
|
fun ffi_pubkymobile_rustbuffer_alloc(`size`: Int,_uniffi_out_err: RustCallStatus,
|
||||||
): RustBuffer.ByValue
|
): RustBuffer.ByValue
|
||||||
fun ffi_pubkymobile_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,_uniffi_out_err: RustCallStatus,
|
fun ffi_pubkymobile_rustbuffer_from_bytes(`bytes`: ForeignBytes.ByValue,_uniffi_out_err: RustCallStatus,
|
||||||
@@ -503,6 +507,10 @@ internal interface _UniFFILib : Library {
|
|||||||
): Short
|
): Short
|
||||||
fun uniffi_pubkymobile_checksum_func_parse_auth_url(
|
fun uniffi_pubkymobile_checksum_func_parse_auth_url(
|
||||||
): Short
|
): Short
|
||||||
|
fun uniffi_pubkymobile_checksum_func_publish(
|
||||||
|
): Short
|
||||||
|
fun uniffi_pubkymobile_checksum_func_resolve(
|
||||||
|
): Short
|
||||||
fun ffi_pubkymobile_uniffi_contract_version(
|
fun ffi_pubkymobile_uniffi_contract_version(
|
||||||
): Int
|
): Int
|
||||||
|
|
||||||
@@ -526,6 +534,12 @@ private fun uniffiCheckApiChecksums(lib: _UniFFILib) {
|
|||||||
if (lib.uniffi_pubkymobile_checksum_func_parse_auth_url() != 29088.toShort()) {
|
if (lib.uniffi_pubkymobile_checksum_func_parse_auth_url() != 29088.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() != 20156.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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Async support
|
// Async support
|
||||||
@@ -628,3 +642,19 @@ fun `parseAuthUrl`(`url`: String): List<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun `publish`(`recordName`: String, `recordContent`: String, `secretKey`: String): List<String> {
|
||||||
|
return FfiConverterSequenceString.lift(
|
||||||
|
rustCall() { _status ->
|
||||||
|
_UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_publish(FfiConverterString.lower(`recordName`),FfiConverterString.lower(`recordContent`),FfiConverterString.lower(`secretKey`),_status)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun `resolve`(`publicKey`: String): List<String> {
|
||||||
|
return FfiConverterSequenceString.lift(
|
||||||
|
rustCall() { _status ->
|
||||||
|
_UniFFILib.INSTANCE.uniffi_pubkymobile_fn_func_resolve(FfiConverterString.lower(`publicKey`),_status)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
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/bridging
|
||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- Yoga
|
- Yoga
|
||||||
- react-native-pubky (0.2.3):
|
- react-native-pubky (0.3.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: 71108903c771df07c623ed14196f0c49d0d49810
|
react-native-pubky: 9fd2633ee974bafa9b77e0cd59e2619a0d9d708d
|
||||||
React-nativeconfig: 4a9543185905fe41014c06776bf126083795aed9
|
React-nativeconfig: 4a9543185905fe41014c06776bf126083795aed9
|
||||||
React-NativeModulesApple: 0506da59fc40d2e1e6e12a233db5e81c46face27
|
React-NativeModulesApple: 0506da59fc40d2e1e6e12a233db5e81c46face27
|
||||||
React-perflogger: 3bbb82f18e9ac29a1a6931568e99d6305ef4403b
|
React-perflogger: 3bbb82f18e9ac29a1a6931568e99d6305ef4403b
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"android": "react-native run-android",
|
"android": "react-native run-android",
|
||||||
"ios": "bundle install && cd ios && pod install && cd ../ && react-native run-ios",
|
"ios": "bundle install && cd ios && pod install && cd ../ && react-native run-ios --simulator \"iPhone 15 Pro\"",
|
||||||
"start": "react-native start",
|
"start": "react-native start",
|
||||||
"build:android": "react-native build-android --extra-params \"--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a\"",
|
"build:android": "react-native build-android --extra-params \"--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a\"",
|
||||||
"install-pods": "bundle install && cd ios && pod install && cd ../",
|
"install-pods": "bundle install && cd ios && pod install && cd ../",
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import { StyleSheet, View, Button } from 'react-native';
|
import { StyleSheet, View, Button } from 'react-native';
|
||||||
import { auth, parseAuthUrl } from '@synonymdev/react-native-pubky';
|
import {
|
||||||
|
auth,
|
||||||
|
parseAuthUrl,
|
||||||
|
publish,
|
||||||
|
resolve,
|
||||||
|
} from '@synonymdev/react-native-pubky';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
@@ -9,7 +14,7 @@ export default function App() {
|
|||||||
onPress={async (): Promise<void> => {
|
onPress={async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const res = await auth(
|
const res = await auth(
|
||||||
'pubkyauth:///?caps=/pub/pubky.app/:rw,/pub/foo.bar/file:r&secret=_K8yj2nS4naHWytpECCX48XhjhGc8KAhlpnuLUiHYBI&relay=http://localhost:52244/',
|
'pubkyauth:///?caps=/pub/pubky.app/:rw,/pub/foo.bar/file:r&secret=U55XnoH6vsMCpx1pxHtt8fReVg4Brvu9C0gUBuw-Jkw&relay=http://167.86.102.121:4173/',
|
||||||
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
||||||
);
|
);
|
||||||
if (res.isErr()) {
|
if (res.isErr()) {
|
||||||
@@ -39,6 +44,42 @@ export default function App() {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Button
|
||||||
|
title={'publish'}
|
||||||
|
onPress={async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
const res = await publish(
|
||||||
|
'recordnametest',
|
||||||
|
'recordcontenttest',
|
||||||
|
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
||||||
|
);
|
||||||
|
if (res.isErr()) {
|
||||||
|
console.log(res.error.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(res.value);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
title={'resolve'}
|
||||||
|
onPress={async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
const res = await resolve(
|
||||||
|
'z4e8s17cou9qmuwen8p1556jzhf1wktmzo6ijsfnri9c4hnrdfty'
|
||||||
|
);
|
||||||
|
if (res.isErr()) {
|
||||||
|
console.log(res.error.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(res.value);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -67,6 +67,10 @@ RustBuffer uniffi_pubkymobile_fn_func_auth(RustBuffer url, RustBuffer secret_key
|
|||||||
);
|
);
|
||||||
RustBuffer uniffi_pubkymobile_fn_func_parse_auth_url(RustBuffer url, RustCallStatus *_Nonnull out_status
|
RustBuffer uniffi_pubkymobile_fn_func_parse_auth_url(RustBuffer url, 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_resolve(RustBuffer public_key, RustCallStatus *_Nonnull out_status
|
||||||
|
);
|
||||||
RustBuffer ffi_pubkymobile_rustbuffer_alloc(int32_t size, RustCallStatus *_Nonnull out_status
|
RustBuffer ffi_pubkymobile_rustbuffer_alloc(int32_t size, RustCallStatus *_Nonnull out_status
|
||||||
);
|
);
|
||||||
RustBuffer ffi_pubkymobile_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status
|
RustBuffer ffi_pubkymobile_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status
|
||||||
@@ -186,6 +190,12 @@ uint16_t uniffi_pubkymobile_checksum_func_auth(void
|
|||||||
);
|
);
|
||||||
uint16_t uniffi_pubkymobile_checksum_func_parse_auth_url(void
|
uint16_t uniffi_pubkymobile_checksum_func_parse_auth_url(void
|
||||||
|
|
||||||
|
);
|
||||||
|
uint16_t uniffi_pubkymobile_checksum_func_publish(void
|
||||||
|
|
||||||
|
);
|
||||||
|
uint16_t uniffi_pubkymobile_checksum_func_resolve(void
|
||||||
|
|
||||||
);
|
);
|
||||||
uint32_t ffi_pubkymobile_uniffi_contract_version(void
|
uint32_t ffi_pubkymobile_uniffi_contract_version(void
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -67,6 +67,10 @@ RustBuffer uniffi_pubkymobile_fn_func_auth(RustBuffer url, RustBuffer secret_key
|
|||||||
);
|
);
|
||||||
RustBuffer uniffi_pubkymobile_fn_func_parse_auth_url(RustBuffer url, RustCallStatus *_Nonnull out_status
|
RustBuffer uniffi_pubkymobile_fn_func_parse_auth_url(RustBuffer url, 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_resolve(RustBuffer public_key, RustCallStatus *_Nonnull out_status
|
||||||
|
);
|
||||||
RustBuffer ffi_pubkymobile_rustbuffer_alloc(int32_t size, RustCallStatus *_Nonnull out_status
|
RustBuffer ffi_pubkymobile_rustbuffer_alloc(int32_t size, RustCallStatus *_Nonnull out_status
|
||||||
);
|
);
|
||||||
RustBuffer ffi_pubkymobile_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status
|
RustBuffer ffi_pubkymobile_rustbuffer_from_bytes(ForeignBytes bytes, RustCallStatus *_Nonnull out_status
|
||||||
@@ -186,6 +190,12 @@ uint16_t uniffi_pubkymobile_checksum_func_auth(void
|
|||||||
);
|
);
|
||||||
uint16_t uniffi_pubkymobile_checksum_func_parse_auth_url(void
|
uint16_t uniffi_pubkymobile_checksum_func_parse_auth_url(void
|
||||||
|
|
||||||
|
);
|
||||||
|
uint16_t uniffi_pubkymobile_checksum_func_publish(void
|
||||||
|
|
||||||
|
);
|
||||||
|
uint16_t uniffi_pubkymobile_checksum_func_resolve(void
|
||||||
|
|
||||||
);
|
);
|
||||||
uint32_t ffi_pubkymobile_uniffi_contract_version(void
|
uint32_t ffi_pubkymobile_uniffi_contract_version(void
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
10
ios/Pubky.mm
10
ios/Pubky.mm
@@ -11,6 +11,16 @@ RCT_EXTERN_METHOD(parseAuthUrl:(NSString *)url
|
|||||||
withResolver:(RCTPromiseResolveBlock)resolve
|
withResolver:(RCTPromiseResolveBlock)resolve
|
||||||
withRejecter:(RCTPromiseRejectBlock)reject)
|
withRejecter:(RCTPromiseRejectBlock)reject)
|
||||||
|
|
||||||
|
RCT_EXTERN_METHOD(publish:(NSString *)recordName
|
||||||
|
recordContent:(NSString *)recordContent
|
||||||
|
secretKey:(NSString *)secretKey
|
||||||
|
withResolver:(RCTPromiseResolveBlock)resolve
|
||||||
|
withRejecter:(RCTPromiseRejectBlock)reject)
|
||||||
|
|
||||||
|
RCT_EXTERN_METHOD(resolve:(NSString *)publicKey
|
||||||
|
withResolver:(RCTPromiseResolveBlock)resolve
|
||||||
|
withRejecter:(RCTPromiseRejectBlock)reject)
|
||||||
|
|
||||||
+ (BOOL)requiresMainQueueSetup
|
+ (BOOL)requiresMainQueueSetup
|
||||||
{
|
{
|
||||||
return NO;
|
return NO;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class Pubky: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc(parseAuthUrl:withResolver:withRejecter:)
|
@objc(parseAuthUrl:withResolver:withRejecter:)
|
||||||
func parseAuthUrl(_ url: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
func parseAuthUrl(_ url: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||||
Task {
|
Task {
|
||||||
@@ -24,4 +25,28 @@ class Pubky: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc(publish:recordContent:secretKey:withResolver:withRejecter:)
|
||||||
|
func publish(recordName: String, recordContent: String, secretKey: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
let result = react_native_pubky.publish(recordName: recordName, recordContent: recordContent, secretKey: secretKey)
|
||||||
|
resolve(result)
|
||||||
|
} catch {
|
||||||
|
reject("publish Error", "Failed to publish", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(resolve:withResolver:withRejecter:)
|
||||||
|
func resolve(publicKey: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
let result = react_native_pubky.resolve(publicKey: publicKey)
|
||||||
|
resolve(result)
|
||||||
|
} catch {
|
||||||
|
reject("resolve Error", "Failed to resolve", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -376,6 +376,26 @@ public func parseAuthUrl(url: String) -> [String] {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func publish(recordName: String, recordContent: String, secretKey: String) -> [String] {
|
||||||
|
return try! FfiConverterSequenceString.lift(
|
||||||
|
try! rustCall() {
|
||||||
|
uniffi_pubkymobile_fn_func_publish(
|
||||||
|
FfiConverterString.lower(recordName),
|
||||||
|
FfiConverterString.lower(recordContent),
|
||||||
|
FfiConverterString.lower(secretKey),$0)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func resolve(publicKey: String) -> [String] {
|
||||||
|
return try! FfiConverterSequenceString.lift(
|
||||||
|
try! rustCall() {
|
||||||
|
uniffi_pubkymobile_fn_func_resolve(
|
||||||
|
FfiConverterString.lower(publicKey),$0)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private enum InitializationResult {
|
private enum InitializationResult {
|
||||||
case ok
|
case ok
|
||||||
case contractVersionMismatch
|
case contractVersionMismatch
|
||||||
@@ -397,6 +417,12 @@ private var initializationResult: InitializationResult {
|
|||||||
if (uniffi_pubkymobile_checksum_func_parse_auth_url() != 29088) {
|
if (uniffi_pubkymobile_checksum_func_parse_auth_url() != 29088) {
|
||||||
return InitializationResult.apiChecksumMismatch
|
return InitializationResult.apiChecksumMismatch
|
||||||
}
|
}
|
||||||
|
if (uniffi_pubkymobile_checksum_func_publish() != 20156) {
|
||||||
|
return InitializationResult.apiChecksumMismatch
|
||||||
|
}
|
||||||
|
if (uniffi_pubkymobile_checksum_func_resolve() != 18303) {
|
||||||
|
return InitializationResult.apiChecksumMismatch
|
||||||
|
}
|
||||||
|
|
||||||
return InitializationResult.ok
|
return InitializationResult.ok
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@synonymdev/react-native-pubky",
|
"name": "@synonymdev/react-native-pubky",
|
||||||
"version": "0.2.3",
|
"version": "0.3.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",
|
||||||
|
|||||||
23
rust/Cargo.lock
generated
23
rust/Cargo.lock
generated
@@ -386,9 +386,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.7.1"
|
version = "1.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
|
checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "camino"
|
name = "camino"
|
||||||
@@ -424,9 +424,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.1.19"
|
version = "1.1.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800"
|
checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
@@ -1566,7 +1566,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "pkarr"
|
name = "pkarr"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
source = "git+https://github.com/Pubky/pkarr?branch=v3#7a4575f4c60689765ba0567aa27248df2b31b2d4"
|
source = "git+https://github.com/Pubky/pkarr?branch=v3#5b2f8e53735f63521b0d587167609a2cb9b8f2ab"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base32",
|
"base32",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -1822,6 +1822,7 @@ dependencies = [
|
|||||||
name = "react_native_pubky"
|
name = "react_native_pubky"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64 0.21.7",
|
||||||
"hex",
|
"hex",
|
||||||
"pkarr",
|
"pkarr",
|
||||||
"pubky",
|
"pubky",
|
||||||
@@ -2504,9 +2505,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.22.20"
|
version = "0.22.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
|
checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -2674,9 +2675,9 @@ checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-normalization"
|
name = "unicode-normalization"
|
||||||
version = "0.1.23"
|
version = "0.1.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
|
checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
@@ -2951,9 +2952,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpki-roots"
|
name = "webpki-roots"
|
||||||
version = "0.26.5"
|
version = "0.26.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a"
|
checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ sha2 = "0.10.8"
|
|||||||
serde = { version = "^1.0.209", features = ["derive"] }
|
serde = { version = "^1.0.209", features = ["derive"] }
|
||||||
tokio = "1.40.0"
|
tokio = "1.40.0"
|
||||||
url = "2.5.2"
|
url = "2.5.2"
|
||||||
pkarr = { git = "https://github.com/Pubky/pkarr", branch = "v3", package = "pkarr", features = ["async", "rand"] }
|
pkarr = { git = "https://github.com/Pubky/pkarr", branch = "v3", features = ["async", "rand"] }
|
||||||
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"
|
||||||
|
|||||||
92
rust/src/auth.rs
Normal file
92
rust/src/auth.rs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
use crate::keypair::get_keypair_from_secret_key;
|
||||||
|
use crate::{PubkyAuthDetails, Capability};
|
||||||
|
use crate::utils::create_response_vector;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use pubky::PubkyClient;
|
||||||
|
use serde_json;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
pub async fn authorize(url: String, secret_key: String) -> Vec<String> {
|
||||||
|
let client = PubkyClient::testnet();
|
||||||
|
let keypair = match get_keypair_from_secret_key(&secret_key) {
|
||||||
|
Ok(keypair) => keypair,
|
||||||
|
Err(error) => return create_response_vector(true, error),
|
||||||
|
};
|
||||||
|
|
||||||
|
// const HOMESERVER: &'static str = "8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo";
|
||||||
|
// const URL: &'static str = "http://localhost:6287?relay=http://demo.httprelay.io/link";
|
||||||
|
// match client.signin(&keypair).await {
|
||||||
|
// Ok(_) => {}, // Signin successful, continue to send_auth_token
|
||||||
|
// Err(_) => {
|
||||||
|
// match client.signup(&keypair, &PublicKey::try_from(HOMESERVER).unwrap()).await {
|
||||||
|
// Ok(_) => {}, // Signup successful, continue to send_auth_token
|
||||||
|
// Err(error) => return create_response_vector(true, format!("Failed to signup: {}", error)),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
let parsed_url = match Url::parse(&url) {
|
||||||
|
Ok(url) => url,
|
||||||
|
Err(_) => return create_response_vector(true, "Failed to parse URL".to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
|
match client.send_auth_token(&keypair, parsed_url).await {
|
||||||
|
Ok(_) => create_response_vector(false, "send_auth_token success".to_string()),
|
||||||
|
Err(error) => create_response_vector(true, format!("send_auth_token failure: {}", error)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pubky_auth_details_to_json(details: &PubkyAuthDetails) -> Result<String, String> {
|
||||||
|
serde_json::to_string(details).map_err(|_| "Error serializing to JSON".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_pubky_auth_url(url_str: &str) -> Result<PubkyAuthDetails, String> {
|
||||||
|
let url = Url::parse(url_str).map_err(|_| "Invalid URL".to_string())?;
|
||||||
|
|
||||||
|
if url.scheme() != "pubkyauth" {
|
||||||
|
return Err("Invalid scheme, expected 'pubkyauth'".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect query pairs into a HashMap for efficient access
|
||||||
|
let query_params: HashMap<_, _> = url.query_pairs().into_owned().collect();
|
||||||
|
|
||||||
|
let relay = query_params
|
||||||
|
.get("relay")
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| "Missing relay".to_string())?;
|
||||||
|
|
||||||
|
let capabilities_str = query_params
|
||||||
|
.get("capabilities")
|
||||||
|
.or_else(|| query_params.get("caps"))
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| "Missing capabilities".to_string())?;
|
||||||
|
|
||||||
|
let secret = query_params
|
||||||
|
.get("secret")
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| "Missing secret".to_string())?;
|
||||||
|
|
||||||
|
// Parse capabilities
|
||||||
|
let capabilities = capabilities_str
|
||||||
|
.split(',')
|
||||||
|
.map(|capability| {
|
||||||
|
let mut parts = capability.splitn(2, ':');
|
||||||
|
let path = parts
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| format!("Invalid capability format in '{}'", capability))?;
|
||||||
|
let permission = parts
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| format!("Invalid capability format in '{}'", capability))?;
|
||||||
|
Ok(Capability {
|
||||||
|
path: path.to_string(),
|
||||||
|
permission: permission.to_string(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, String>>()?;
|
||||||
|
|
||||||
|
Ok(PubkyAuthDetails {
|
||||||
|
relay,
|
||||||
|
capabilities,
|
||||||
|
secret,
|
||||||
|
})
|
||||||
|
}
|
||||||
17
rust/src/keypair.rs
Normal file
17
rust/src/keypair.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
use pkarr::Keypair;
|
||||||
|
|
||||||
|
pub fn get_keypair_from_secret_key(secret_key: &str) -> Result<Keypair, String> {
|
||||||
|
let bytes = match hex::decode(&secret_key) {
|
||||||
|
Ok(bytes) => bytes,
|
||||||
|
Err(_) => return Err("Failed to decode secret key".to_string())
|
||||||
|
};
|
||||||
|
|
||||||
|
let secret_key_bytes: [u8; 32] = match bytes.try_into() {
|
||||||
|
Ok(secret_key) => secret_key,
|
||||||
|
Err(_) => {
|
||||||
|
return Err("Failed to convert secret key to 32-byte array".to_string());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Keypair::from_secret_key(&secret_key_bytes))
|
||||||
|
}
|
||||||
226
rust/src/lib.rs
226
rust/src/lib.rs
@@ -1,48 +1,138 @@
|
|||||||
|
mod types;
|
||||||
|
mod keypair;
|
||||||
|
mod auth;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
|
pub use types::*;
|
||||||
|
pub use keypair::*;
|
||||||
|
pub use auth::*;
|
||||||
|
pub use utils::*;
|
||||||
|
|
||||||
uniffi::setup_scaffolding!();
|
uniffi::setup_scaffolding!();
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use base64::Engine;
|
||||||
|
use base64::engine::general_purpose;
|
||||||
use pubky::PubkyClient;
|
use pubky::PubkyClient;
|
||||||
use hex;
|
use hex;
|
||||||
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::dns::rdata::RData;
|
||||||
|
use pkarr::dns::ResourceRecord;
|
||||||
|
use serde_json::json;
|
||||||
|
use utils::*;
|
||||||
|
|
||||||
async fn authorize(url: String, secret_key: String) -> Vec<String> {
|
#[uniffi::export]
|
||||||
let bytes = match hex::decode(&secret_key) {
|
fn resolve(public_key: String) -> Vec<String> {
|
||||||
Ok(bytes) => bytes,
|
let public_key = match public_key.as_str().try_into() {
|
||||||
Err(_) => return create_response_vector(true, "Failed to decode secret key".to_string())
|
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 secret_key_bytes: [u8; 32] = match bytes.try_into() {
|
match client.resolve(&public_key) {
|
||||||
Ok(secret_key) => secret_key,
|
Ok(Some(signed_packet)) => {
|
||||||
Err(_) => {
|
// Collect references to ResourceRecords from the signed packet's answers
|
||||||
return create_response_vector(true, "Failed to convert secret key to 32-byte array".to_string());
|
let all_records: Vec<&ResourceRecord> = signed_packet.packet().answers.iter().collect();
|
||||||
|
// Convert each ResourceRecord to a JSON value, handling errors appropriately
|
||||||
|
let json_records: Vec<serde_json::Value> = all_records
|
||||||
|
.iter()
|
||||||
|
.filter_map(|record| {
|
||||||
|
match resource_record_to_json(record) {
|
||||||
|
Ok(json_value) => Some(json_value),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Error converting record to JSON: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
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 dns_packet = &bytes[104..];
|
||||||
|
|
||||||
|
let json_obj = json!({
|
||||||
|
"public_key": general_purpose::STANDARD.encode(public_key),
|
||||||
|
"signature": general_purpose::STANDARD.encode(signature),
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"dns_packet": general_purpose::STANDARD.encode(dns_packet),
|
||||||
|
"records": json_records
|
||||||
|
});
|
||||||
|
|
||||||
|
let json_str = serde_json::to_string(&json_obj)
|
||||||
|
.expect("Failed to convert JSON object to string");
|
||||||
|
|
||||||
|
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]
|
||||||
|
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)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let keypair = match get_keypair_from_secret_key(&secret_key) {
|
||||||
|
Ok(keypair) => keypair,
|
||||||
|
Err(error) => return create_response_vector(true, error),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut packet = dns::Packet::new_reply(0);
|
||||||
|
|
||||||
|
let dns_name = match dns::Name::new(&record_name) {
|
||||||
|
Ok(name) => name,
|
||||||
|
Err(e) => return create_response_vector(true, format!("Failed to create DNS name: {}", e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let record_content_str: &str = record_content.as_str();
|
||||||
|
|
||||||
|
let txt_record = match record_content_str.try_into() {
|
||||||
|
Ok(value) => RData::TXT(value),
|
||||||
|
Err(e) => {
|
||||||
|
return create_response_vector(true, format!("Failed to convert string to TXT record: {}", e))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let client = PubkyClient::testnet();
|
packet.answers.push(dns::ResourceRecord::new(
|
||||||
let keypair = pkarr::Keypair::from_secret_key(&secret_key_bytes);
|
dns_name,
|
||||||
|
dns::CLASS::IN,
|
||||||
|
30,
|
||||||
|
txt_record,
|
||||||
|
));
|
||||||
|
|
||||||
// const HOMESERVER: &'static str = "8pinxxgqs41n4aididenw5apqp1urfmzdztr8jt4abrkdn435ewo";
|
match SignedPacket::from_packet(&keypair, &packet) {
|
||||||
// const URL: &'static str = "http://localhost:6287?relay=http://demo.httprelay.io/link";
|
Ok(signed_packet) => {
|
||||||
// match client.signin(&keypair).await {
|
match client.publish(&signed_packet) {
|
||||||
// Ok(_) => {}, // Signin successful, continue to send_auth_token
|
Ok(()) => {
|
||||||
// Err(_) => {
|
create_response_vector(false, keypair.public_key().to_string())
|
||||||
// match client.signup(&keypair, &PublicKey::try_from(HOMESERVER).unwrap()).await {
|
}
|
||||||
// Ok(_) => {}, // Signup successful, continue to send_auth_token
|
Err(e) => {
|
||||||
// Err(error) => return create_response_vector(true, format!("Failed to signup: {}", error)),
|
create_response_vector(true, format!("Failed to publish: {}", e))
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
Err(e) => {
|
||||||
let parsed_url = match Url::parse(&url) {
|
create_response_vector(true, format!("Failed to create signed packet: {}", e))
|
||||||
Ok(url) => url,
|
}
|
||||||
Err(_) => return create_response_vector(true, "Failed to parse URL".to_string()),
|
|
||||||
};
|
|
||||||
|
|
||||||
match client.send_auth_token(&keypair, parsed_url).await {
|
|
||||||
Ok(_) => create_response_vector(false, "send_auth_token success".to_string()),
|
|
||||||
Err(error) => create_response_vector(true, format!("send_auth_token failure: {}", error)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,79 +154,3 @@ fn parse_auth_url(url: String) -> Vec<String> {
|
|||||||
Err(error) => create_response_vector(true, error),
|
Err(error) => create_response_vector(true, error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
|
||||||
struct Capability {
|
|
||||||
path: String,
|
|
||||||
permission: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
|
||||||
struct PubkyAuthDetails {
|
|
||||||
relay: String,
|
|
||||||
capabilities: Vec<Capability>,
|
|
||||||
secret: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pubky_auth_details_to_json(details: &PubkyAuthDetails) -> Result<String, String> {
|
|
||||||
serde_json::to_string(details).map_err(|_| "Error serializing to JSON".to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_pubky_auth_url(url_str: &str) -> Result<PubkyAuthDetails, String> {
|
|
||||||
let url = Url::parse(url_str).map_err(|_| "Invalid URL".to_string())?;
|
|
||||||
|
|
||||||
if url.scheme() != "pubkyauth" {
|
|
||||||
return Err("Invalid scheme, expected 'pubkyauth'".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect query pairs into a HashMap for efficient access
|
|
||||||
let query_params: HashMap<_, _> = url.query_pairs().into_owned().collect();
|
|
||||||
|
|
||||||
let relay = query_params
|
|
||||||
.get("relay")
|
|
||||||
.cloned()
|
|
||||||
.ok_or_else(|| "Missing relay".to_string())?;
|
|
||||||
|
|
||||||
let capabilities_str = query_params
|
|
||||||
.get("capabilities")
|
|
||||||
.or_else(|| query_params.get("caps"))
|
|
||||||
.cloned()
|
|
||||||
.ok_or_else(|| "Missing capabilities".to_string())?;
|
|
||||||
|
|
||||||
let secret = query_params
|
|
||||||
.get("secret")
|
|
||||||
.cloned()
|
|
||||||
.ok_or_else(|| "Missing secret".to_string())?;
|
|
||||||
|
|
||||||
// Parse capabilities
|
|
||||||
let capabilities = capabilities_str
|
|
||||||
.split(',')
|
|
||||||
.map(|capability| {
|
|
||||||
let mut parts = capability.splitn(2, ':');
|
|
||||||
let path = parts
|
|
||||||
.next()
|
|
||||||
.ok_or_else(|| format!("Invalid capability format in '{}'", capability))?;
|
|
||||||
let permission = parts
|
|
||||||
.next()
|
|
||||||
.ok_or_else(|| format!("Invalid capability format in '{}'", capability))?;
|
|
||||||
Ok(Capability {
|
|
||||||
path: path.to_string(),
|
|
||||||
permission: permission.to_string(),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>, String>>()?;
|
|
||||||
|
|
||||||
Ok(PubkyAuthDetails {
|
|
||||||
relay,
|
|
||||||
capabilities,
|
|
||||||
secret,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_response_vector(error: bool, data: String) -> Vec<String> {
|
|
||||||
if error {
|
|
||||||
vec!["error".to_string(), data]
|
|
||||||
} else {
|
|
||||||
vec!["success".to_string(), data]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
14
rust/src/types.rs
Normal file
14
rust/src/types.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct Capability {
|
||||||
|
pub path: String,
|
||||||
|
pub permission: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct PubkyAuthDetails {
|
||||||
|
pub relay: String,
|
||||||
|
pub capabilities: Vec<Capability>,
|
||||||
|
pub secret: String,
|
||||||
|
}
|
||||||
203
rust/src/utils.rs
Normal file
203
rust/src/utils.rs
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||||
|
use serde_json::json;
|
||||||
|
use base64::{engine::general_purpose, Engine};
|
||||||
|
use pkarr::dns::rdata::RData;
|
||||||
|
use pkarr::dns::ResourceRecord;
|
||||||
|
|
||||||
|
pub fn create_response_vector(error: bool, data: String) -> Vec<String> {
|
||||||
|
if error {
|
||||||
|
vec!["error".to_string(), data]
|
||||||
|
} else {
|
||||||
|
vec!["success".to_string(), data]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extract_rdata_for_json(record: &ResourceRecord) -> serde_json::Value {
|
||||||
|
match &record.rdata {
|
||||||
|
RData::TXT(txt) => {
|
||||||
|
let attributes = txt.attributes();
|
||||||
|
let strings: Vec<String> = attributes.into_iter()
|
||||||
|
.map(|(key, value)| {
|
||||||
|
match value {
|
||||||
|
Some(v) => format!("{}={}", key, v),
|
||||||
|
None => key,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
json!({
|
||||||
|
"type": "TXT",
|
||||||
|
"strings": strings
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::A(a) => {
|
||||||
|
let ipv4 = Ipv4Addr::from(a.address);
|
||||||
|
json!({
|
||||||
|
"type": "A",
|
||||||
|
"address": ipv4.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::AAAA(aaaa) => {
|
||||||
|
let ipv6 = Ipv6Addr::from(aaaa.address);
|
||||||
|
json!({
|
||||||
|
"type": "AAAA",
|
||||||
|
"address": ipv6.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::AFSDB(afsdb) => {
|
||||||
|
json!({
|
||||||
|
"type": "AFSDB",
|
||||||
|
"subtype": afsdb.subtype,
|
||||||
|
"hostname": afsdb.hostname.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::CAA(caa) => {
|
||||||
|
json!({
|
||||||
|
"type": "CAA",
|
||||||
|
"flag": caa.flag,
|
||||||
|
"tag": caa.tag.to_string(),
|
||||||
|
"value": caa.value.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::HINFO(hinfo) => {
|
||||||
|
json!({
|
||||||
|
"type": "HINFO",
|
||||||
|
"cpu": hinfo.cpu.to_string(),
|
||||||
|
"os": hinfo.os.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::ISDN(isdn) => {
|
||||||
|
json!({
|
||||||
|
"type": "ISDN",
|
||||||
|
"address": isdn.address.to_string(),
|
||||||
|
"sa": isdn.sa.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::LOC(loc) => {
|
||||||
|
json!({
|
||||||
|
"type": "LOC",
|
||||||
|
"version": loc.version,
|
||||||
|
"size": loc.size,
|
||||||
|
"horizontal_precision": loc.horizontal_precision,
|
||||||
|
"vertical_precision": loc.vertical_precision,
|
||||||
|
"latitude": loc.latitude,
|
||||||
|
"longitude": loc.longitude,
|
||||||
|
"altitude": loc.altitude
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::MINFO(minfo) => {
|
||||||
|
json!({
|
||||||
|
"type": "MINFO",
|
||||||
|
"rmailbox": minfo.rmailbox.to_string(),
|
||||||
|
"emailbox": minfo.emailbox.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::MX(mx) => {
|
||||||
|
json!({
|
||||||
|
"type": "MX",
|
||||||
|
"preference": mx.preference,
|
||||||
|
"exchange": mx.exchange.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::NAPTR(naptr) => {
|
||||||
|
json!({
|
||||||
|
"type": "NAPTR",
|
||||||
|
"order": naptr.order,
|
||||||
|
"preference": naptr.preference,
|
||||||
|
"flags": naptr.flags.to_string(),
|
||||||
|
"services": naptr.services.to_string(),
|
||||||
|
"regexp": naptr.regexp.to_string(),
|
||||||
|
"replacement": naptr.replacement.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::NULL(_, null_record) => {
|
||||||
|
json!({
|
||||||
|
"type": "NULL",
|
||||||
|
"data": base64::encode(null_record.get_data())
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::OPT(opt) => {
|
||||||
|
json!({
|
||||||
|
"type": "OPT",
|
||||||
|
"udp_packet_size": opt.udp_packet_size,
|
||||||
|
"version": opt.version,
|
||||||
|
"opt_codes": opt.opt_codes.iter().map(|code| {
|
||||||
|
json!({
|
||||||
|
"code": code.code,
|
||||||
|
"data": base64::encode(&code.data)
|
||||||
|
})
|
||||||
|
}).collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::RouteThrough(rt) => {
|
||||||
|
json!({
|
||||||
|
"type": "RT",
|
||||||
|
"preference": rt.preference,
|
||||||
|
"intermediate_host": rt.intermediate_host.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::RP(rp) => {
|
||||||
|
json!({
|
||||||
|
"type": "RP",
|
||||||
|
"mbox": rp.mbox.to_string(),
|
||||||
|
"txt": rp.txt.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::SOA(soa) => {
|
||||||
|
json!({
|
||||||
|
"type": "SOA",
|
||||||
|
"mname": soa.mname.to_string(),
|
||||||
|
"rname": soa.rname.to_string(),
|
||||||
|
"serial": soa.serial,
|
||||||
|
"refresh": soa.refresh,
|
||||||
|
"retry": soa.retry,
|
||||||
|
"expire": soa.expire,
|
||||||
|
"minimum": soa.minimum
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::SRV(srv) => {
|
||||||
|
json!({
|
||||||
|
"type": "SRV",
|
||||||
|
"priority": srv.priority,
|
||||||
|
"weight": srv.weight,
|
||||||
|
"port": srv.port,
|
||||||
|
"target": srv.target.to_string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::SVCB(svcb) => {
|
||||||
|
let mut params = serde_json::Map::new();
|
||||||
|
for (key, value) in svcb.iter_params() {
|
||||||
|
params.insert(key.to_string(), json!(base64::encode(value)));
|
||||||
|
}
|
||||||
|
json!({
|
||||||
|
"type": "SVCB",
|
||||||
|
"priority": svcb.priority,
|
||||||
|
"target": svcb.target.to_string(),
|
||||||
|
"params": params
|
||||||
|
})
|
||||||
|
},
|
||||||
|
RData::WKS(wks) => {
|
||||||
|
json!({
|
||||||
|
"type": "WKS",
|
||||||
|
"address": Ipv4Addr::from(wks.address).to_string(),
|
||||||
|
"protocol": wks.protocol,
|
||||||
|
"bit_map": base64::encode(&wks.bit_map)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => json!({
|
||||||
|
"type": format!("{:?}", record.rdata.type_code()),
|
||||||
|
"data": "Unhandled record type"
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resource_record_to_json(record: &ResourceRecord) -> Result<serde_json::Value, Box<dyn Error>> {
|
||||||
|
Ok(json!({
|
||||||
|
"name": record.name.to_string(),
|
||||||
|
"class": format!("{:?}", record.class),
|
||||||
|
"ttl": record.ttl,
|
||||||
|
"rdata": extract_rdata_for_json(record),
|
||||||
|
"cache_flush": record.cache_flush
|
||||||
|
}))
|
||||||
|
}
|
||||||
@@ -54,3 +54,48 @@ export async function parseAuthUrl(
|
|||||||
return err(JSON.stringify(e));
|
return err(JSON.stringify(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function publish(
|
||||||
|
recordName: string,
|
||||||
|
recordContent: string,
|
||||||
|
secretKey: string
|
||||||
|
): Promise<Result<string[]>> {
|
||||||
|
try {
|
||||||
|
const res = await Pubky.publish(recordName, recordContent, secretKey);
|
||||||
|
if (res[0] === 'error') {
|
||||||
|
return err(res[1]);
|
||||||
|
}
|
||||||
|
return ok(res[1]);
|
||||||
|
} catch (e) {
|
||||||
|
return err(JSON.stringify(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ITxt {
|
||||||
|
cache_flush: boolean;
|
||||||
|
class: string;
|
||||||
|
name: string;
|
||||||
|
rdata: {
|
||||||
|
strings: string[];
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
ttl: number;
|
||||||
|
}
|
||||||
|
interface IDNSPacket {
|
||||||
|
dns_packet: string;
|
||||||
|
public_key: string;
|
||||||
|
records: ITxt[];
|
||||||
|
signature: string;
|
||||||
|
timestamp: number;
|
||||||
|
}
|
||||||
|
export async function resolve(publicKey: string): Promise<Result<IDNSPacket>> {
|
||||||
|
try {
|
||||||
|
const res = await Pubky.resolve(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