feat: generate secret key

Adds generate_secret_key & get_public_key_from_secret_key functions.
Adds generate_secret_key & get_public_key_from_secret_key functions examples to README.md.
Fix list error on Android.
Bump package version to 0.7.0.
This commit is contained in:
coreyphillips
2024-09-29 15:12:44 -04:00
parent ab9ba2360b
commit 2fec48a4ad
16 changed files with 284 additions and 30 deletions

View File

@@ -19,6 +19,8 @@ npm install @synonymdev/react-native-pubky
- [x] [put](#put): Upload a small payload to a given path.
- [x] [get](#get): Download a small payload from a given path relative to a pubky author.
- [x] [list](#list): Returns a list of Pubky URLs of the files in the path of the `url` provided.
- [x] [generateSecretKey](#generateSecretKey): Generate a secret key.
- [x] [getPublicKeyFromSecretKey](#getPublicKeyFromSecretKey): Get the public key string and uri from a secret key.
### Methods to be Implemented
- [ ] signIn: Sign-in to a homeserver.
- [ ] signUp: Sign-up to a homeserver and update Pkarr accordingly.
@@ -154,6 +156,30 @@ if (listRes.isErr()) {
console.log(listRes.value);
```
### <a name="generateSecretKey"></a>generateSecretKey
```js
import { generateSecretKey } from '@synonymdev/react-native-pubky';
const generateSecretKeyRes = await generateSecretKey();
if (generateSecretKeyRes.isErr()) {
console.log(generateSecretKeyRes.error.message);
return;
}
console.log(generateSecretKeyRes.value);
```
### <a name="getPublicKeyFromSecretKey"></a>getPublicKeyFromSecretKey
```js
import { getPublicKeyFromSecretKey } from '@synonymdev/react-native-pubky';
const getPublicKeyFromSecretKeyRes = await getPublicKeyFromSecretKey('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855');
if (getPublicKeyFromSecretKeyRes.isErr()) {
console.log(getPublicKeyFromSecretKeyRes.error.message);
return;
}
console.log(getPublicKeyFromSecretKeyRes.value);
```
## Local Installation
1. Clone & npm install:

View File

@@ -9,17 +9,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import uniffi.pubkymobile.auth
import uniffi.pubkymobile.parseAuthUrl
import uniffi.pubkymobile.publish
import uniffi.pubkymobile.resolve
import uniffi.pubkymobile.signUp
import uniffi.pubkymobile.signIn
import uniffi.pubkymobile.signOut
import uniffi.pubkymobile.put
import uniffi.pubkymobile.get
import uniffi.pubkymobile.publishHttps
import uniffi.pubkymobile.resolveHttps
import uniffi.pubkymobile.*
class PubkyModule(reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) {
@@ -250,6 +240,44 @@ class PubkyModule(reactContext: ReactApplicationContext) :
}
}
@ReactMethod
fun generateSecretKey(promise: Promise) {
CoroutineScope(Dispatchers.IO).launch {
try {
val result = generate_secret_key()
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 getPublicKeyFromSecretKey(secretKey: String, promise: Promise) {
CoroutineScope(Dispatchers.IO).launch {
try {
val result = getPublicKeyFromSecretKey(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)
}
}
}
}
companion object {
const val NAME = "Pubky"
}

View File

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

View File

@@ -12,6 +12,8 @@ import {
resolveHttps,
publishHttps,
list,
generateSecretKey,
getPublicKeyFromSecretKey,
} from '@synonymdev/react-native-pubky';
export default function App() {
@@ -226,6 +228,39 @@ export default function App() {
}
}}
/>
<Button
title={'generateSecretKey'}
onPress={async (): Promise<void> => {
try {
const res = await generateSecretKey();
if (res.isErr()) {
console.log(res.error.message);
return;
}
console.log('Generated Secret Key:', res.value);
} catch (e) {
console.log(e);
}
}}
/>
<Button
title={'getPublicKeyFromSecretKey'}
onPress={async (): Promise<void> => {
try {
const res = await getPublicKeyFromSecretKey(
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' // Secret Key
);
if (res.isErr()) {
console.log(res.error.message);
return;
}
console.log(res.value);
} catch (e) {
console.log(e);
}
}}
/>
</View>
);
}

View File

@@ -4,6 +4,22 @@
<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>
@@ -22,22 +38,6 @@
<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>

View File

@@ -64,9 +64,14 @@ typedef void (*UniFfiRustFutureContinuation)(void * _Nonnull, int8_t);
// Scaffolding functions
RustBuffer uniffi_pubkymobile_fn_func_auth(RustBuffer url, RustBuffer secret_key, RustCallStatus *_Nonnull out_status
);
RustBuffer uniffi_pubkymobile_fn_func_generate_secret_key(RustCallStatus *_Nonnull out_status
);
void* _Nonnull uniffi_pubkymobile_fn_func_get(RustBuffer url
);
RustBuffer uniffi_pubkymobile_fn_func_get_public_key_from_secret_key(RustBuffer secret_key, RustCallStatus *_Nonnull out_status
);
RustBuffer uniffi_pubkymobile_fn_func_list(RustBuffer url, RustCallStatus *_Nonnull out_status
);
RustBuffer uniffi_pubkymobile_fn_func_parse_auth_url(RustBuffer url, RustCallStatus *_Nonnull out_status
@@ -203,9 +208,15 @@ void ffi_pubkymobile_rust_future_complete_void(void* _Nonnull handle, RustCallSt
);
uint16_t uniffi_pubkymobile_checksum_func_auth(void
);
uint16_t uniffi_pubkymobile_checksum_func_generate_secret_key(void
);
uint16_t uniffi_pubkymobile_checksum_func_get(void
);
uint16_t uniffi_pubkymobile_checksum_func_get_public_key_from_secret_key(void
);
uint16_t uniffi_pubkymobile_checksum_func_list(void

View File

@@ -64,9 +64,14 @@ typedef void (*UniFfiRustFutureContinuation)(void * _Nonnull, int8_t);
// Scaffolding functions
RustBuffer uniffi_pubkymobile_fn_func_auth(RustBuffer url, RustBuffer secret_key, RustCallStatus *_Nonnull out_status
);
RustBuffer uniffi_pubkymobile_fn_func_generate_secret_key(RustCallStatus *_Nonnull out_status
);
void* _Nonnull uniffi_pubkymobile_fn_func_get(RustBuffer url
);
RustBuffer uniffi_pubkymobile_fn_func_get_public_key_from_secret_key(RustBuffer secret_key, RustCallStatus *_Nonnull out_status
);
RustBuffer uniffi_pubkymobile_fn_func_list(RustBuffer url, RustCallStatus *_Nonnull out_status
);
RustBuffer uniffi_pubkymobile_fn_func_parse_auth_url(RustBuffer url, RustCallStatus *_Nonnull out_status
@@ -203,9 +208,15 @@ void ffi_pubkymobile_rust_future_complete_void(void* _Nonnull handle, RustCallSt
);
uint16_t uniffi_pubkymobile_checksum_func_auth(void
);
uint16_t uniffi_pubkymobile_checksum_func_generate_secret_key(void
);
uint16_t uniffi_pubkymobile_checksum_func_get(void
);
uint16_t uniffi_pubkymobile_checksum_func_get_public_key_from_secret_key(void
);
uint16_t uniffi_pubkymobile_checksum_func_list(void

View File

@@ -57,6 +57,13 @@ RCT_EXTERN_METHOD(list:(NSString *)url
withResolver:(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(generateSecretKey:(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(getPublicKeyFromSecretKey:(NSString *)secretKey
withResolver:(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject)
+ (BOOL)requiresMainQueueSetup
{
return NO;

View File

@@ -143,4 +143,28 @@ class Pubky: NSObject {
}
}
}
@objc(generateSecretKey:withRejecter:)
func generateSecretKey(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
Task {
do {
let result = react_native_pubky.generateSecretKey()
resolve(result)
} catch {
reject("generateSecretKey Error", "Failed to generate secret key", error)
}
}
}
@objc(getPublicKeyFromSecretKey:withResolver:withRejecter:)
func getPublicKeyFromSecretKey(_ secretKey: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
Task {
do {
let result = react_native_pubky.getPublicKeyFromSecretKey(secretKey: secretKey)
resolve(result)
} catch {
reject("getPublicKeyFromSecretKey Error", "Failed to get public key", error)
}
}
}
}

View File

@@ -429,6 +429,14 @@ public func auth(url: String, secretKey: String) -> [String] {
)
}
public func generateSecretKey() -> [String] {
return try! FfiConverterSequenceString.lift(
try! rustCall() {
uniffi_pubkymobile_fn_func_generate_secret_key($0)
}
)
}
public func get(url: String) async -> [String] {
return try! await uniffiRustCallAsync(
rustFutureFunc: {
@@ -447,6 +455,15 @@ public func get(url: String) async -> [String] {
public func getPublicKeyFromSecretKey(secretKey: String) -> [String] {
return try! FfiConverterSequenceString.lift(
try! rustCall() {
uniffi_pubkymobile_fn_func_get_public_key_from_secret_key(
FfiConverterString.lower(secretKey),$0)
}
)
}
public func list(url: String) -> [String] {
return try! FfiConverterSequenceString.lift(
try! rustCall() {
@@ -597,9 +614,15 @@ private var initializationResult: InitializationResult {
if (uniffi_pubkymobile_checksum_func_auth() != 61378) {
return InitializationResult.apiChecksumMismatch
}
if (uniffi_pubkymobile_checksum_func_generate_secret_key() != 63116) {
return InitializationResult.apiChecksumMismatch
}
if (uniffi_pubkymobile_checksum_func_get() != 5395) {
return InitializationResult.apiChecksumMismatch
}
if (uniffi_pubkymobile_checksum_func_get_public_key_from_secret_key() != 23603) {
return InitializationResult.apiChecksumMismatch
}
if (uniffi_pubkymobile_checksum_func_list() != 8522) {
return InitializationResult.apiChecksumMismatch
}

View File

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

View File

@@ -1,5 +1,8 @@
use pkarr::Keypair;
/**
* Get a keypair from a secret key
*/
pub fn get_keypair_from_secret_key(secret_key: &str) -> Result<Keypair, String> {
let bytes = match hex::decode(&secret_key) {
Ok(bytes) => bytes,
@@ -14,4 +17,18 @@ pub fn get_keypair_from_secret_key(secret_key: &str) -> Result<Keypair, String>
};
Ok(Keypair::from_secret_key(&secret_key_bytes))
}
/**
* Get the secret key from a keypair
*/
pub fn get_secret_key_from_keypair(keypair: &Keypair) -> String {
hex::encode(keypair.secret_key())
}
/**
* Generate a new keypair
*/
pub fn generate_keypair() -> Keypair {
Keypair::random()
}

View File

@@ -46,6 +46,45 @@ static TOKIO_RUNTIME: Lazy<Arc<Runtime>> = Lazy::new(|| {
)
});
#[uniffi::export]
pub fn generate_secret_key() -> Vec<String> {
let keypair = generate_keypair();
let secret_key = get_secret_key_from_keypair(&keypair);
let public_key = keypair.public_key();
let uri = public_key.to_uri_string();
let json_obj = json!({
"secret_key": secret_key,
"public_key": public_key.to_string(),
"uri": uri,
});
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)
}
#[uniffi::export]
pub fn get_public_key_from_secret_key(secret_key: String) -> Vec<String> {
let keypair = match get_keypair_from_secret_key(&secret_key) {
Ok(keypair) => keypair,
Err(error) => return create_response_vector(true, error),
};
let public_key = keypair.public_key();
let uri = public_key.to_uri_string();
let json_obj = json!({
"public_key": public_key.to_string(),
"uri": uri,
});
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)
}
#[uniffi::export]
pub fn publish_https(record_name: String, target: String, secret_key: String) -> Vec<String> {
let client = PKARR_CLIENT.clone();

View File

@@ -224,3 +224,36 @@ export async function list(url: string): Promise<Result<string[]>> {
return err(JSON.stringify(e));
}
}
interface IPublicKeyInfo {
public_key: string;
uri: string;
}
interface IGenerateSecretKey extends IPublicKeyInfo {
secret_key: string;
}
export async function generateSecretKey(): Promise<Result<IGenerateSecretKey>> {
try {
const res = await Pubky.generateSecretKey();
if (res[0] === 'error') {
return err(res[1]);
}
return ok(JSON.parse(res[1]));
} catch (e) {
return err(JSON.stringify(e));
}
}
export async function getPublicKeyFromSecretKey(
secretKey: string
): Promise<Result<IPublicKeyInfo>> {
try {
const res = await Pubky.getPublicKeyFromSecretKey(secretKey);
if (res[0] === 'error') {
return err(res[1]);
}
return ok(JSON.parse(res[1]));
} catch (e) {
return err(JSON.stringify(e));
}
}