mirror of
https://github.com/meshcore-dev/meshcore.js.git
synced 2026-04-20 22:13:49 +00:00
- Restore behavioral descriptions for sendCommandExportContact and getNeighbours - Use string literal union for AdvertParsedData.type and Advert.getTypeString() - Remove on/once/off overrides that provided minimal type-safety value
133 lines
3.5 KiB
JavaScript
133 lines
3.5 KiB
JavaScript
import BufferReader from "./buffer_reader.js";
|
|
import BufferWriter from "./buffer_writer.js";
|
|
|
|
/** @typedef {import("./types.js").AdvertParsedData} AdvertParsedData */
|
|
|
|
class Advert {
|
|
|
|
static ADV_TYPE_NONE = 0;
|
|
static ADV_TYPE_CHAT = 1;
|
|
static ADV_TYPE_REPEATER = 2;
|
|
static ADV_TYPE_ROOM = 3;
|
|
|
|
static ADV_LATLON_MASK = 0x10;
|
|
static ADV_FEAT1_MASK = 0x20;
|
|
static ADV_FEAT2_MASK = 0x40;
|
|
static ADV_NAME_MASK = 0x80;
|
|
|
|
/**
|
|
* @param {Uint8Array} publicKey
|
|
* @param {number} timestamp
|
|
* @param {Uint8Array} signature
|
|
* @param {Uint8Array} appData
|
|
*/
|
|
constructor(publicKey, timestamp, signature, appData) {
|
|
this.publicKey = publicKey;
|
|
this.timestamp = timestamp;
|
|
this.signature = signature;
|
|
this.appData = appData;
|
|
/** @type {AdvertParsedData} */
|
|
this.parsed = this.parseAppData();
|
|
}
|
|
|
|
/**
|
|
* @param {Uint8Array} bytes
|
|
* @returns {Advert}
|
|
*/
|
|
static fromBytes(bytes) {
|
|
|
|
// read bytes
|
|
const bufferReader = new BufferReader(bytes);
|
|
const publicKey = bufferReader.readBytes(32);
|
|
const timestamp = bufferReader.readUInt32LE();
|
|
const signature = bufferReader.readBytes(64);
|
|
const appData = bufferReader.readRemainingBytes();
|
|
|
|
return new Advert(publicKey, timestamp, signature, appData);
|
|
|
|
}
|
|
|
|
/** @returns {number} */
|
|
getFlags() {
|
|
return this.appData[0];
|
|
}
|
|
|
|
/** @returns {number} */
|
|
getType() {
|
|
const flags = this.getFlags();
|
|
return flags & 0x0F;
|
|
}
|
|
|
|
/** @returns {"NONE" | "CHAT" | "REPEATER" | "ROOM" | null} */
|
|
getTypeString() {
|
|
const type = this.getType();
|
|
if(type === Advert.ADV_TYPE_NONE) return "NONE";
|
|
if(type === Advert.ADV_TYPE_CHAT) return "CHAT";
|
|
if(type === Advert.ADV_TYPE_REPEATER) return "REPEATER";
|
|
if(type === Advert.ADV_TYPE_ROOM) return "ROOM";
|
|
return null;
|
|
}
|
|
|
|
/** @returns {Promise<boolean>} */
|
|
async isVerified() {
|
|
|
|
const { ed25519 } = await import("@noble/curves/ed25519");
|
|
|
|
// build signed data
|
|
const bufferWriter = new BufferWriter();
|
|
bufferWriter.writeBytes(this.publicKey);
|
|
bufferWriter.writeUInt32LE(this.timestamp);
|
|
bufferWriter.writeBytes(this.appData);
|
|
|
|
// verify signature
|
|
return ed25519.verify(this.signature, bufferWriter.toBytes(), this.publicKey);
|
|
|
|
}
|
|
|
|
/** @returns {AdvertParsedData} */
|
|
parseAppData() {
|
|
|
|
// read app data
|
|
const bufferReader = new BufferReader(this.appData);
|
|
const flags = bufferReader.readByte();
|
|
|
|
// parse lat lon
|
|
var lat = null;
|
|
var lon = null;
|
|
if(flags & Advert.ADV_LATLON_MASK){
|
|
lat = bufferReader.readInt32LE();
|
|
lon = bufferReader.readInt32LE();
|
|
}
|
|
|
|
// parse feat1
|
|
var feat1 = null;
|
|
if(flags & Advert.ADV_FEAT1_MASK){
|
|
feat1 = bufferReader.readUInt16LE();
|
|
}
|
|
|
|
// parse feat2
|
|
var feat2 = null;
|
|
if(flags & Advert.ADV_FEAT2_MASK){
|
|
feat2 = bufferReader.readUInt16LE();
|
|
}
|
|
|
|
// parse name (remainder of app data)
|
|
var name = null;
|
|
if(flags & Advert.ADV_NAME_MASK){
|
|
name = bufferReader.readString();
|
|
}
|
|
|
|
return {
|
|
type: this.getTypeString(),
|
|
lat: lat,
|
|
lon: lon,
|
|
name: name,
|
|
feat1: feat1,
|
|
feat2: feat2,
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export default Advert;
|