Compare commits

...

8 Commits

Author SHA1 Message Date
Anton Iakimov
284f9a0992
fix: update wakuv2 fleet DNS discovery enrtree
https://github.com/status-im/infra-misc/issues/171
2023-09-27 13:36:26 +02:00
Richard Ramos
49ea163a59 feat: expose DNS Discovery and DiscV5 2023-02-26 20:09:29 -04:00
Brice Stacey
dc6ab3cf27 fix: add serializers for encrypted payloads
The encrypted functions have slightly different APIs, so we decorate the
WakuMessage and only change its toJSON function.
2023-02-10 09:29:49 -04:00
Brice Stacey
dd1f2a222b chore: include go-waku download scripts in releases
Since go-waku needs to be downloaded, including these download scripts
in the releases is helpful.
2023-02-10 09:29:49 -04:00
Brice Stacey
dff2d0259b fix: update package.json
I had forgotten to include it in the PR #15
2023-02-10 09:29:49 -04:00
Brice Stacey
6757cd4dd0 fix: typo calling decodeSymmetric instead of decodeAsymmetric 2023-02-09 10:49:46 -04:00
Brice Stacey
7040e63e41 fix: replace base-64 with more robust Buffer
The original implementation was using a combination of atob and the
base-64 library. Buffer is a more common and robust solution.
2023-02-09 10:49:46 -04:00
Brice Stacey
2ed5c9b376 fix: add missing pods script in the example project 2023-02-09 10:49:46 -04:00
11 changed files with 4671 additions and 80 deletions

View File

@ -183,4 +183,8 @@ class ReactNativeModule(reactContext: ReactApplicationContext) : ReactContextBas
promise.resolve(Gowaku.filterUnsubscribe(filterJSON, ms.toLong())) promise.resolve(Gowaku.filterUnsubscribe(filterJSON, ms.toLong()))
} }
@ReactMethod
fun dnsDiscovery(url: String, nameserver: String = "", ms: Double, promise: Promise) {
promise.resolve(Gowaku.dnsDiscovery(url, nameserver, ms.toLong()))
}
} }

View File

@ -30,11 +30,11 @@ mkdir -p tmp
cd tmp cd tmp
rm -f ${SHA_FILE} rm -f ${SHA_FILE}
wget "https://github.com/status-im/go-waku/releases/download/v${VERSION}/${SHA_FILE}" wget "https://github.com/waku-org/go-waku/releases/download/v${VERSION}/${SHA_FILE}"
if [ "$DOWNLOAD_ANDROID" = true ]; then if [ "$DOWNLOAD_ANDROID" = true ]; then
rm -f ${ANDROID_TAR} rm -f ${ANDROID_TAR}
wget "https://github.com/status-im/go-waku/releases/download/v${VERSION}/${ANDROID_TAR}" curl -L "https://github.com/waku-org/go-waku/releases/download/v${VERSION}/${ANDROID_TAR}" --output $ANDROID_TAR
sha256sum --status --ignore-missing -c ${SHA_FILE} sha256sum --status --ignore-missing -c ${SHA_FILE}
if ! sha256sum --status --ignore-missing -c ${SHA_FILE}; then if ! sha256sum --status --ignore-missing -c ${SHA_FILE}; then
echo "checksum failed - verify download" echo "checksum failed - verify download"
@ -47,7 +47,7 @@ fi
if [ "$DOWNLOAD_IOS" = true ]; then if [ "$DOWNLOAD_IOS" = true ]; then
rm -f ${IOS_TAR} rm -f ${IOS_TAR}
wget "https://github.com/status-im/go-waku/releases/download/v${VERSION}/${IOS_TAR}" curl -L "https://github.com/waku-org/go-waku/releases/download/v${VERSION}/${IOS_TAR}" --output $IOS_TAR
if ! sha256sum --status --ignore-missing -c ${SHA_FILE}; then if ! sha256sum --status --ignore-missing -c ${SHA_FILE}; then
echo "checksum failed - verify download" echo "checksum failed - verify download"

View File

@ -24,8 +24,11 @@ import {
FilterSubscription, FilterSubscription,
ContentFilter, ContentFilter,
filterSubscribe, filterSubscribe,
dnsDiscovery,
} from '@waku/react-native'; } from '@waku/react-native';
const myContentTopic = '/example/1/react-native-app/proto';
export default function App() { export default function App() {
const [result, setResult] = React.useState(); const [result, setResult] = React.useState();
@ -39,14 +42,16 @@ export default function App() {
} }
console.log('The node ID:', await peerID()); console.log('The node ID:', await peerID());
await relaySubscribe(); await relaySubscribe();
onMessage((event) => { onMessage((event) => {
if (event.wakuMessage.contentTopic !== myContentTopic) return;
setResult( setResult(
'Message received: ' + 'Message received: ' +
event.wakuMessage.timestamp + event.wakuMessage.timestamp +
' - payload:[' + ' - payload:[' +
event.wakuMessage.payload + JSON.stringify(event.wakuMessage.payload) +
']' ']'
); );
console.log('Message received: ', event); console.log('Message received: ', event);
@ -80,7 +85,7 @@ export default function App() {
console.log('Peers', await peers()); console.log('Peers', await peers());
let msg = new WakuMessage(); let msg = new WakuMessage();
msg.contentTopic = 'ABC'; msg.contentTopic = myContentTopic;
msg.payload = new Uint8Array([1, 2, 3, 4, 5]); msg.payload = new Uint8Array([1, 2, 3, 4, 5]);
msg.timestamp = new Date(); msg.timestamp = new Date();
msg.version = 0; msg.version = 0;
@ -92,13 +97,21 @@ export default function App() {
// TO RETRIEVE HISTORIC MESSAGES: // TO RETRIEVE HISTORIC MESSAGES:
console.log('Retrieving messages from store node'); console.log('Retrieving messages from store node');
const query = new StoreQuery(); const query = new StoreQuery();
query.contentFilters.push(new ContentFilter('ABC')); query.contentFilters.push(new ContentFilter(myContentTopic));
const queryResult = await storeQuery( const queryResult = await storeQuery(
query, query,
'16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm' '16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm'
); );
console.log(queryResult); console.log(queryResult);
// DNS Discovery
console.log('Retrieving Nodes using DNS Discovery');
const dnsDiscoveryResult = await dnsDiscovery(
'enrtree://AO47IDOLBKH72HIZZOXQP6NMRESAN7CHYWIBNXDXWRJRZWLODKII6@test.wakuv2.nodes.status.im',
'1.1.1.1'
);
console.log(dnsDiscoveryResult);
// USING FILTER INSTEAD OF RELAY: // USING FILTER INSTEAD OF RELAY:
// Instantiate the node passing these parameters: // Instantiate the node passing these parameters:
// let config = new Config(); // let config = new Config();

View File

@ -21,11 +21,11 @@
}, },
"..": { "..": {
"name": "@waku/react-native", "name": "@waku/react-native",
"version": "0.0.12", "version": "0.2.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"base-64": "^1.0.0", "big-integer": "^1.6.51",
"big-integer": "^1.6.51" "buffer": "^6.0.3"
}, },
"devDependencies": { "devDependencies": {
"@arkweid/lefthook": "^0.7.7", "@arkweid/lefthook": "^0.7.7",
@ -14055,8 +14055,8 @@
"@types/jest": "^28.1.2", "@types/jest": "^28.1.2",
"@types/react": "~17.0.21", "@types/react": "~17.0.21",
"@types/react-native": "0.68.0", "@types/react-native": "0.68.0",
"base-64": "^1.0.0",
"big-integer": "^1.6.51", "big-integer": "^1.6.51",
"buffer": "^6.0.3",
"commitlint": "^17.0.2", "commitlint": "^17.0.2",
"eslint": "^8.4.1", "eslint": "^8.4.1",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",

View File

@ -7,7 +7,8 @@
"start": "expo start --dev-client", "start": "expo start --dev-client",
"android": "expo run:android", "android": "expo run:android",
"ios": "expo run:ios", "ios": "expo run:ios",
"web": "expo start --web" "web": "expo start --web",
"pods": "npx pod-install"
}, },
"dependencies": { "dependencies": {
"@waku/react-native": "file:../", "@waku/react-native": "file:../",

View File

@ -1 +1 @@
0.3.1 0.5.1

View File

@ -146,5 +146,11 @@ RCT_EXTERN_METHOD(filterUnsubscribe:(NSString *)filterJSON
withResolver:(RCTPromiseResolveBlock)resolve withResolver:(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject) withRejecter:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(dnsDiscovery:(NSString *)url
withNameserver:(NSString *)nameserver
withMs:(nonnull NSNumber *)ms
withResolver:(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject)
@end @end

View File

@ -177,4 +177,9 @@ class ReactNative: RCTEventEmitter {
resolve(GowakuFilterUnsubscribe(filterJSON, ms)) resolve(GowakuFilterUnsubscribe(filterJSON, ms))
} }
@objc(dnsDiscovery:withNameserver:withMs:withResolver:withRejecter:)
func dnsDiscovery(url: String, nameserver: String, ms: Int, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
resolve(GowakuDnsDiscovery(url, nameserver, ms))
}
} }

4549
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "@waku/react-native", "name": "@waku/react-native",
"version": "0.1.0", "version": "0.2.0",
"description": "Waku React Native", "description": "Waku React Native",
"author": "Status Research & Development GMBH", "author": "Status Research & Development GMBH",
"authors": [ "authors": [
@ -21,6 +21,8 @@
"android", "android",
"ios", "ios",
"cpp", "cpp",
"download-gowaku.sh",
"go-waku.VERSION",
"waku-react-native.podspec", "waku-react-native.podspec",
"!lib/typescript/example", "!lib/typescript/example",
"!android/build", "!android/build",
@ -36,6 +38,7 @@
"prepare": "bob build", "prepare": "bob build",
"release": "release-it", "release": "release-it",
"example": "yarn --cwd example", "example": "yarn --cwd example",
"pods": "npx pod-install",
"bootstrap": "yarn example && yarn && yarn example pods" "bootstrap": "yarn example && yarn && yarn example pods"
}, },
"keywords": [ "keywords": [
@ -158,7 +161,7 @@
] ]
}, },
"dependencies": { "dependencies": {
"base-64": "^1.0.0", "big-integer": "^1.6.51",
"big-integer": "^1.6.51" "buffer": "^6.0.3"
} }
} }

View File

@ -1,6 +1,6 @@
import { NativeModules, Platform, NativeEventEmitter } from 'react-native'; import { NativeModules, Platform, NativeEventEmitter } from 'react-native';
import { decode, encode } from 'base-64';
import bigInt from 'big-integer'; import bigInt from 'big-integer';
import { Buffer } from 'buffer';
const LINKING_ERROR = const LINKING_ERROR =
`The package '@waku/react-native' doesn't seem to be linked. Make sure: \n\n` + `The package '@waku/react-native' doesn't seem to be linked. Make sure: \n\n` +
@ -28,14 +28,13 @@ export class WakuMessage {
timestamp?: Date = undefined; timestamp?: Date = undefined;
toJSON() { toJSON() {
const b64encoded = encode(String.fromCharCode(...this.payload));
return { return {
contentTopic: this.contentTopic, contentTopic: this.contentTopic,
version: this.version, version: this.version,
timestamp: this.timestamp timestamp: this.timestamp
? bigInt(this.timestamp.valueOf()).multiply(OneMillion).toString(10) ? bigInt(this.timestamp.valueOf()).multiply(OneMillion).toString(10)
: 0, : 0,
payload: b64encoded, payload: Buffer.from(this.payload).toString('base64'),
}; };
} }
} }
@ -57,24 +56,25 @@ export function onMessage(cb: (arg0: any) => void) {
: undefined; : undefined;
signal.event.wakuMessage.version = msg.version || 0; signal.event.wakuMessage.version = msg.version || 0;
signal.event.wakuMessage.contentTopic = msg.contentTopic; signal.event.wakuMessage.contentTopic = msg.contentTopic;
signal.event.wakuMessage.payload = new Uint8Array( signal.event.wakuMessage.payload = Buffer.from(msg.payload || [], 'base64');
decode(msg.payload ?? [])
.split('')
.map((c: any) => c.charCodeAt(0))
);
cb(signal.event); cb(signal.event);
}); });
} }
export class Config { export class Config {
host: String | null = null; host: String | null = null; // IP address. Default 0.0.0.0
port: Number | null = null; port: Number | null = null; // TCP port to listen. Default 60000. Use 0 for random
advertiseAddr: String | null = null; advertiseAddr: String | null = null; // Advertise custom multiaddress
nodeKey: String | null = null; nodeKey: String | null = null; // secp256k1 private key. Default random
keepAliveInterval: Number | null = null; keepAliveInterval: Number | null = null; // interval in seconds to ping all peers
relay: Boolean | null = null; relay: Boolean | null = null; // enable waku relay
filter: Boolean | null = null; relayTopics: Array<String> = []; // array of pubsub topics that WakuRelay will automatically subscribe to when the node starts
minPeersToPublish: Number | null = null; minPeersToPublish: Number | null = null;
filter: Boolean | null = null; // enable waku filter
discv5: Boolean | null = null; // enable discv5
discV5BootstrapNodes: Array<String> = []; // array of bootstrap nodes ENR
discV5UDPPort: Number | null = null; // UDP port for DiscoveryV5
logLevel: String | null = null; // Set the log level. Default `INFO`. Allowed values "DEBUG", "INFO", "WARN", "ERROR", "DPANIC", "PANIC", "FATAL"
} }
/** /**
@ -382,6 +382,27 @@ export function peerCnt(): Promise<Number> {
}); });
} }
export class EncryptedPayload extends WakuMessage {
constructor(msg: WakuMessage) {
super();
this.contentTopic = msg.contentTopic;
this.version = msg.version;
this.timestamp = msg.timestamp;
this.payload = msg.payload;
}
toJSON() {
return {
contentTopic: this.contentTopic,
version: this.version,
timestamp: this.timestamp
? bigInt(this.timestamp.valueOf()).multiply(OneMillion).toJSNumber()
: 0,
payload: Buffer.from(Array.from(this.payload)).toString('base64'),
};
}
}
export class DecodedPayload { export class DecodedPayload {
payload: Uint8Array = new Uint8Array(); payload: Uint8Array = new Uint8Array();
padding: Uint8Array = new Uint8Array(); padding: Uint8Array = new Uint8Array();
@ -389,11 +410,9 @@ export class DecodedPayload {
signature: String | null = ''; signature: String | null = '';
toJSON() { toJSON() {
const b64payload = encode(String.fromCharCode(...this.payload));
const b64padding = encode(String.fromCharCode(...this.padding));
return { return {
payload: b64payload, payload: Buffer.from(this.payload).toString('base64'),
padding: b64padding, padding: Buffer.from(this.padding).toString('base64'),
pubkey: this.pubkey, pubkey: this.pubkey,
signature: this.signature, signature: this.signature,
}; };
@ -411,7 +430,8 @@ export function decodeSymmetric(
symmetricKey: String symmetricKey: String
): Promise<DecodedPayload> { ): Promise<DecodedPayload> {
return new Promise<DecodedPayload>(async (resolve, reject) => { return new Promise<DecodedPayload>(async (resolve, reject) => {
let messageJSON = JSON.stringify(msg); let message = new EncryptedPayload(msg);
let messageJSON = JSON.stringify(message);
let response = JSON.parse( let response = JSON.parse(
await ReactNative.decodeSymmetric(messageJSON, symmetricKey) await ReactNative.decodeSymmetric(messageJSON, symmetricKey)
); );
@ -419,16 +439,8 @@ export function decodeSymmetric(
reject(response.error); reject(response.error);
} else { } else {
let decodedPayload = new DecodedPayload(); let decodedPayload = new DecodedPayload();
decodedPayload.payload = new Uint8Array( decodedPayload.payload = Buffer.from(response.result.data, 'base64');
atob(response.result.payload) decodedPayload.padding = Buffer.from(response.result.padding, 'base64');
.split('')
.map((c) => c.charCodeAt(0))
);
decodedPayload.padding = new Uint8Array(
atob(response.result.padding)
.split('')
.map((c) => c.charCodeAt(0))
);
decodedPayload.pubkey = response.result.pubkey; decodedPayload.pubkey = response.result.pubkey;
decodedPayload.signature = response.result.signature; decodedPayload.signature = response.result.signature;
resolve(decodedPayload); resolve(decodedPayload);
@ -447,24 +459,17 @@ export function decodeAsymmetric(
privateKey: String privateKey: String
): Promise<DecodedPayload> { ): Promise<DecodedPayload> {
return new Promise<DecodedPayload>(async (resolve, reject) => { return new Promise<DecodedPayload>(async (resolve, reject) => {
let messageJSON = JSON.stringify(msg); let message = new EncryptedPayload(msg);
let messageJSON = JSON.stringify(message);
let response = JSON.parse( let response = JSON.parse(
await ReactNative.decodeSymmetric(messageJSON, privateKey) await ReactNative.decodeAsymmetric(messageJSON, privateKey)
); );
if (response.error) { if (response.error) {
reject(response.error); reject(response.error);
} else { } else {
let decodedPayload = new DecodedPayload(); let decodedPayload = new DecodedPayload();
decodedPayload.payload = new Uint8Array( decodedPayload.payload = Buffer.from(response.result.data, 'base64');
atob(response.result.payload) decodedPayload.padding = Buffer.from(response.result.padding, 'base64');
.split('')
.map((c) => c.charCodeAt(0))
);
decodedPayload.padding = new Uint8Array(
atob(response.result.padding)
.split('')
.map((c) => c.charCodeAt(0))
);
decodedPayload.pubkey = response.result.pubkey; decodedPayload.pubkey = response.result.pubkey;
decodedPayload.signature = response.result.signature; decodedPayload.signature = response.result.signature;
resolve(decodedPayload); resolve(decodedPayload);
@ -557,7 +562,8 @@ export function lightpushPublishEncAsymmetric(
timeoutMs: Number = 0 timeoutMs: Number = 0
): Promise<string> { ): Promise<string> {
return new Promise<string>(async (resolve, reject) => { return new Promise<string>(async (resolve, reject) => {
let messageJSON = JSON.stringify(msg); let message = new EncryptedPayload(msg);
let messageJSON = JSON.stringify(message);
let response = JSON.parse( let response = JSON.parse(
await ReactNative.lightpushPublishEncodeAsymmetric( await ReactNative.lightpushPublishEncodeAsymmetric(
messageJSON, messageJSON,
@ -595,7 +601,8 @@ export function lightpushPublishEncSymmetric(
timeoutMs: Number = 0 timeoutMs: Number = 0
): Promise<string> { ): Promise<string> {
return new Promise<string>(async (resolve, reject) => { return new Promise<string>(async (resolve, reject) => {
let messageJSON = JSON.stringify(msg); let message = new EncryptedPayload(msg);
let messageJSON = JSON.stringify(message);
let response = JSON.parse( let response = JSON.parse(
await ReactNative.lightpushPublishEncodeAsymmetric( await ReactNative.lightpushPublishEncodeAsymmetric(
messageJSON, messageJSON,
@ -652,6 +659,45 @@ export function peers(): Promise<Array<Peer>> {
}); });
} }
export class DiscoveredNode {
peerID: String = '';
addrs: Array<String> = Array();
enr: String = '';
constructor(
peerID: String,
addrs: Array<String>,
enr: String
) {
this.peerID = peerID;
this.addrs = addrs;
this.enr = enr;
}
}
/**
* Use DNS Discovery to retrieve a list of nodes from an enrtree:// URL
* @return List of Nodes
*/
export function dnsDiscovery(
url: String,
nameserver: String,
timeoutMs: Number = 0
): Promise<Array<DiscoveredNode>> {
return new Promise<Array<DiscoveredNode>>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.dnsDiscovery(url, nameserver, timeoutMs));
if (response.error) {
reject(response.error);
} else {
resolve(
response.result.map(
(x: any) => new DiscoveredNode(x.peerID, x.multiaddrs, x.enr)
)
);
}
});
}
export class Index { export class Index {
digest: Uint8Array = new Uint8Array(); digest: Uint8Array = new Uint8Array();
receiverTime: Number = 0; receiverTime: Number = 0;
@ -745,9 +791,7 @@ export function storeQuery(
? new Date(bigInt(t).divide(OneMillion).toJSNumber()) ? new Date(bigInt(t).divide(OneMillion).toJSNumber())
: undefined; : undefined;
response.result.messages[i].payload = new Uint8Array( response.result.messages[i].payload = new Uint8Array(
decode(response.result.messages[i].payload ?? []) Buffer.from(response.result.messages[i].payload ?? [], 'base64')
.split('')
.map((c) => c.charCodeAt(0))
); );
} }
} }