@droponair/sdk-js 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/LICENSE +21 -0
- package/README.md +865 -0
- package/dist/core/bytes.d.ts +8 -0
- package/dist/core/bytes.js +75 -0
- package/dist/core/messaging-client.d.ts +159 -0
- package/dist/core/messaging-client.js +1293 -0
- package/dist/core/session-manager.d.ts +6 -0
- package/dist/core/session-manager.js +18 -0
- package/dist/core/types.d.ts +173 -0
- package/dist/core/types.js +2 -0
- package/dist/crypto/crypto-service.d.ts +28 -0
- package/dist/crypto/crypto-service.js +100 -0
- package/dist/crypto/payload-format.d.ts +8 -0
- package/dist/crypto/payload-format.js +63 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +29 -0
- package/dist/storage/indexeddb-key-storage.d.ts +9 -0
- package/dist/storage/indexeddb-key-storage.js +70 -0
- package/dist/storage/memory-key-storage.d.ts +7 -0
- package/dist/storage/memory-key-storage.js +18 -0
- package/dist/transport/protobuf-codec.d.ts +138 -0
- package/dist/transport/protobuf-codec.js +337 -0
- package/dist/version.d.ts +22 -0
- package/dist/version.js +25 -0
- package/package.json +49 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/** Per-device encrypted payload on the wire. */
|
|
2
|
+
export interface WireDeviceEncryptedPayload {
|
|
3
|
+
deviceId: string;
|
|
4
|
+
encryptedPayload: Uint8Array;
|
|
5
|
+
senderPublicKey: Uint8Array;
|
|
6
|
+
}
|
|
7
|
+
export interface WireEnvelope {
|
|
8
|
+
messageId: string;
|
|
9
|
+
appId: string;
|
|
10
|
+
fromUserId: string;
|
|
11
|
+
toUserId: string;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
encryptedPayload: Uint8Array;
|
|
14
|
+
clientMessageId?: string;
|
|
15
|
+
/** Multi-device: per-device encrypted payloads. */
|
|
16
|
+
devicePayloads?: WireDeviceEncryptedPayload[];
|
|
17
|
+
/** Sender's device ID. */
|
|
18
|
+
senderDeviceId?: string;
|
|
19
|
+
/** 0 = E2EE (default), 1 = CLEARTEXT */
|
|
20
|
+
encryptionType?: number;
|
|
21
|
+
/** Populated only when encryptionType = CLEARTEXT. */
|
|
22
|
+
plaintextPayload?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface WireAck {
|
|
25
|
+
messageId: string;
|
|
26
|
+
type: string;
|
|
27
|
+
}
|
|
28
|
+
export interface WireEvent {
|
|
29
|
+
type: string;
|
|
30
|
+
reason?: string;
|
|
31
|
+
metadata?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface WireCallFrame {
|
|
34
|
+
type: string;
|
|
35
|
+
callId?: string;
|
|
36
|
+
targetUserId?: string;
|
|
37
|
+
payload?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface WireBroadcastFrame {
|
|
40
|
+
broadcastId: string;
|
|
41
|
+
appId: string;
|
|
42
|
+
channelId: string;
|
|
43
|
+
publisherId: string;
|
|
44
|
+
timestamp: number;
|
|
45
|
+
encryptionType: number;
|
|
46
|
+
encryptedPayload: Uint8Array;
|
|
47
|
+
plaintextPayload: string;
|
|
48
|
+
sequenceNumber: number;
|
|
49
|
+
}
|
|
50
|
+
export interface WireBroadcastNotification {
|
|
51
|
+
broadcastId: string;
|
|
52
|
+
channelId: string;
|
|
53
|
+
publisherId: string;
|
|
54
|
+
timestamp: number;
|
|
55
|
+
encryptionType: number;
|
|
56
|
+
encryptedPayload: Uint8Array;
|
|
57
|
+
plaintextPayload: string;
|
|
58
|
+
sequenceNumber: number;
|
|
59
|
+
}
|
|
60
|
+
export interface WireGroupMemberPayload {
|
|
61
|
+
userId: string;
|
|
62
|
+
devicePayloads: WireDeviceEncryptedPayload[];
|
|
63
|
+
}
|
|
64
|
+
export interface WireGroupEnvelope {
|
|
65
|
+
messageId: string;
|
|
66
|
+
groupId: string;
|
|
67
|
+
fromUserId: string;
|
|
68
|
+
senderDeviceId: string;
|
|
69
|
+
memberPayloads: WireGroupMemberPayload[];
|
|
70
|
+
encryptionType: number;
|
|
71
|
+
plaintextPayload?: string;
|
|
72
|
+
timestamp: number;
|
|
73
|
+
}
|
|
74
|
+
export interface WireGroupMessageNotification {
|
|
75
|
+
messageId: string;
|
|
76
|
+
groupId: string;
|
|
77
|
+
fromUserId: string;
|
|
78
|
+
senderDeviceId: string;
|
|
79
|
+
devicePayloads: WireDeviceEncryptedPayload[];
|
|
80
|
+
encryptionType: number;
|
|
81
|
+
plaintextPayload?: string;
|
|
82
|
+
timestamp: number;
|
|
83
|
+
}
|
|
84
|
+
export interface WireGroupAck {
|
|
85
|
+
messageId: string;
|
|
86
|
+
groupId: string;
|
|
87
|
+
type: string;
|
|
88
|
+
}
|
|
89
|
+
export interface WireGroupCallFrame {
|
|
90
|
+
type: string;
|
|
91
|
+
callId: string;
|
|
92
|
+
groupId: string;
|
|
93
|
+
targetUserId?: string;
|
|
94
|
+
payload?: string;
|
|
95
|
+
}
|
|
96
|
+
export type InboundFrame = {
|
|
97
|
+
kind: 'envelope';
|
|
98
|
+
data: WireEnvelope;
|
|
99
|
+
} | {
|
|
100
|
+
kind: 'ack';
|
|
101
|
+
data: WireAck;
|
|
102
|
+
} | {
|
|
103
|
+
kind: 'event';
|
|
104
|
+
data: WireEvent;
|
|
105
|
+
} | {
|
|
106
|
+
kind: 'call';
|
|
107
|
+
data: WireCallFrame;
|
|
108
|
+
} | {
|
|
109
|
+
kind: 'broadcast';
|
|
110
|
+
data: WireBroadcastNotification;
|
|
111
|
+
} | {
|
|
112
|
+
kind: 'groupMessage';
|
|
113
|
+
data: WireGroupMessageNotification;
|
|
114
|
+
} | {
|
|
115
|
+
kind: 'groupAck';
|
|
116
|
+
data: WireGroupAck;
|
|
117
|
+
} | {
|
|
118
|
+
kind: 'groupCall';
|
|
119
|
+
data: WireGroupCallFrame;
|
|
120
|
+
};
|
|
121
|
+
export declare class ProtobufCodec {
|
|
122
|
+
encodeEnvelope(value: WireEnvelope): Uint8Array;
|
|
123
|
+
encodeAck(value: WireAck): Uint8Array;
|
|
124
|
+
encodeCallFrame(value: WireCallFrame): Uint8Array;
|
|
125
|
+
encodeBroadcastFrame(value: WireBroadcastFrame): Uint8Array;
|
|
126
|
+
encodeGroupEnvelope(value: WireGroupEnvelope): Uint8Array;
|
|
127
|
+
encodeGroupCallFrame(value: WireGroupCallFrame): Uint8Array;
|
|
128
|
+
encodeGroupAck(value: WireGroupAck): Uint8Array;
|
|
129
|
+
decodeFrame(payload: Uint8Array): InboundFrame;
|
|
130
|
+
private tryDecodeEnvelope;
|
|
131
|
+
private tryDecodeAck;
|
|
132
|
+
private tryDecodeEvent;
|
|
133
|
+
private tryDecodeCallFrame;
|
|
134
|
+
private tryDecodeBroadcastNotification;
|
|
135
|
+
private tryDecodeGroupMessageNotification;
|
|
136
|
+
private tryDecodeGroupAck;
|
|
137
|
+
private tryDecodeGroupCallFrame;
|
|
138
|
+
}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ProtobufCodec = void 0;
|
|
37
|
+
const protobuf = __importStar(require("protobufjs/light"));
|
|
38
|
+
// EncryptionType enum: E2EE = 0, CLEARTEXT = 1
|
|
39
|
+
const EncryptionTypeEnum = new protobuf.Enum('EncryptionType', { E2EE: 0, CLEARTEXT: 1 });
|
|
40
|
+
// Per-device encrypted payload for multi-device E2EE
|
|
41
|
+
const DeviceEncryptedPayloadType = new protobuf.Type('DeviceEncryptedPayload')
|
|
42
|
+
.add(new protobuf.Field('deviceId', 1, 'string'))
|
|
43
|
+
.add(new protobuf.Field('encryptedPayload', 2, 'bytes'))
|
|
44
|
+
.add(new protobuf.Field('senderPublicKey', 3, 'bytes'));
|
|
45
|
+
const EnvelopeType = new protobuf.Type('Envelope')
|
|
46
|
+
.add(EncryptionTypeEnum)
|
|
47
|
+
.add(DeviceEncryptedPayloadType) // nested type must be added first
|
|
48
|
+
.add(new protobuf.Field('messageId', 1, 'string'))
|
|
49
|
+
.add(new protobuf.Field('appId', 2, 'string'))
|
|
50
|
+
.add(new protobuf.Field('fromUserId', 3, 'string'))
|
|
51
|
+
.add(new protobuf.Field('toUserId', 4, 'string'))
|
|
52
|
+
.add(new protobuf.Field('timestamp', 5, 'int64'))
|
|
53
|
+
.add(new protobuf.Field('encryptedPayload', 6, 'bytes'))
|
|
54
|
+
.add(new protobuf.Field('clientMessageId', 7, 'string'))
|
|
55
|
+
.add(new protobuf.Field('devicePayloads', 8, 'DeviceEncryptedPayload', 'repeated'))
|
|
56
|
+
.add(new protobuf.Field('senderDeviceId', 9, 'string'))
|
|
57
|
+
.add(new protobuf.Field('encryptionType', 10, 'EncryptionType'))
|
|
58
|
+
.add(new protobuf.Field('plaintextPayload', 11, 'string'));
|
|
59
|
+
const AckType = new protobuf.Type('Ack')
|
|
60
|
+
.add(new protobuf.Field('messageId', 1, 'string'))
|
|
61
|
+
.add(new protobuf.Field('type', 2, 'string'));
|
|
62
|
+
const EventType = new protobuf.Type('Event')
|
|
63
|
+
.add(new protobuf.Field('type', 1, 'string'))
|
|
64
|
+
.add(new protobuf.Field('reason', 2, 'string'))
|
|
65
|
+
.add(new protobuf.Field('metadata', 3, 'string'));
|
|
66
|
+
const CallFrameType = new protobuf.Type('CallFrame')
|
|
67
|
+
.add(new protobuf.Field('type', 1, 'string'))
|
|
68
|
+
.add(new protobuf.Field('callId', 2, 'string'))
|
|
69
|
+
.add(new protobuf.Field('targetUserId', 3, 'string'))
|
|
70
|
+
.add(new protobuf.Field('payload', 4, 'string'));
|
|
71
|
+
// EncryptionType enum for standalone types (BroadcastFrame/BroadcastNotification)
|
|
72
|
+
const BroadcastEncryptionTypeEnum = new protobuf.Enum('EncryptionType', { E2EE: 0, CLEARTEXT: 1 });
|
|
73
|
+
const BroadcastFrameType = new protobuf.Type('BroadcastFrame')
|
|
74
|
+
.add(BroadcastEncryptionTypeEnum)
|
|
75
|
+
.add(new protobuf.Field('broadcastId', 1, 'string'))
|
|
76
|
+
.add(new protobuf.Field('appId', 2, 'string'))
|
|
77
|
+
.add(new protobuf.Field('channelId', 3, 'string'))
|
|
78
|
+
.add(new protobuf.Field('publisherId', 4, 'string'))
|
|
79
|
+
.add(new protobuf.Field('timestamp', 5, 'int64'))
|
|
80
|
+
.add(new protobuf.Field('encryptionType', 6, 'EncryptionType'))
|
|
81
|
+
.add(new protobuf.Field('encryptedPayload', 7, 'bytes'))
|
|
82
|
+
.add(new protobuf.Field('plaintextPayload', 8, 'string'))
|
|
83
|
+
.add(new protobuf.Field('sequenceNumber', 9, 'int32'));
|
|
84
|
+
const BroadcastNotifEncryptionTypeEnum = new protobuf.Enum('EncryptionType', { E2EE: 0, CLEARTEXT: 1 });
|
|
85
|
+
const BroadcastNotificationType = new protobuf.Type('BroadcastNotification')
|
|
86
|
+
.add(BroadcastNotifEncryptionTypeEnum)
|
|
87
|
+
.add(new protobuf.Field('broadcastId', 1, 'string'))
|
|
88
|
+
.add(new protobuf.Field('channelId', 2, 'string'))
|
|
89
|
+
.add(new protobuf.Field('publisherId', 3, 'string'))
|
|
90
|
+
.add(new protobuf.Field('timestamp', 4, 'int64'))
|
|
91
|
+
.add(new protobuf.Field('encryptionType', 5, 'EncryptionType'))
|
|
92
|
+
.add(new protobuf.Field('encryptedPayload', 6, 'bytes'))
|
|
93
|
+
.add(new protobuf.Field('plaintextPayload', 7, 'string'))
|
|
94
|
+
.add(new protobuf.Field('sequenceNumber', 8, 'int32'));
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Group messaging types
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
const GroupMemberPayloadDeviceType = new protobuf.Type('DeviceEncryptedPayload')
|
|
99
|
+
.add(new protobuf.Field('deviceId', 1, 'string'))
|
|
100
|
+
.add(new protobuf.Field('encryptedPayload', 2, 'bytes'))
|
|
101
|
+
.add(new protobuf.Field('senderPublicKey', 3, 'bytes'));
|
|
102
|
+
const GroupMemberPayloadType = new protobuf.Type('GroupMemberPayload')
|
|
103
|
+
.add(GroupMemberPayloadDeviceType)
|
|
104
|
+
.add(new protobuf.Field('userId', 1, 'string'))
|
|
105
|
+
.add(new protobuf.Field('devicePayloads', 2, 'DeviceEncryptedPayload', 'repeated'));
|
|
106
|
+
const GroupEnvelopeEncryptionTypeEnum = new protobuf.Enum('EncryptionType', { E2EE: 0, CLEARTEXT: 1 });
|
|
107
|
+
const GroupEnvelopeType = new protobuf.Type('GroupEnvelope')
|
|
108
|
+
.add(GroupEnvelopeEncryptionTypeEnum)
|
|
109
|
+
.add(GroupMemberPayloadType)
|
|
110
|
+
.add(new protobuf.Field('messageId', 1, 'string'))
|
|
111
|
+
.add(new protobuf.Field('groupId', 2, 'string'))
|
|
112
|
+
.add(new protobuf.Field('fromUserId', 3, 'string'))
|
|
113
|
+
.add(new protobuf.Field('senderDeviceId', 4, 'string'))
|
|
114
|
+
.add(new protobuf.Field('memberPayloads', 5, 'GroupMemberPayload', 'repeated'))
|
|
115
|
+
.add(new protobuf.Field('encryptionType', 6, 'EncryptionType'))
|
|
116
|
+
.add(new protobuf.Field('plaintextPayload', 7, 'string'))
|
|
117
|
+
.add(new protobuf.Field('timestamp', 8, 'int64'));
|
|
118
|
+
const GroupNotifEncryptionTypeEnum = new protobuf.Enum('EncryptionType', { E2EE: 0, CLEARTEXT: 1 });
|
|
119
|
+
const GroupNotifDeviceType = new protobuf.Type('DeviceEncryptedPayload')
|
|
120
|
+
.add(new protobuf.Field('deviceId', 1, 'string'))
|
|
121
|
+
.add(new protobuf.Field('encryptedPayload', 2, 'bytes'))
|
|
122
|
+
.add(new protobuf.Field('senderPublicKey', 3, 'bytes'));
|
|
123
|
+
const GroupMessageNotificationType = new protobuf.Type('GroupMessageNotification')
|
|
124
|
+
.add(GroupNotifEncryptionTypeEnum)
|
|
125
|
+
.add(GroupNotifDeviceType)
|
|
126
|
+
.add(new protobuf.Field('messageId', 1, 'string'))
|
|
127
|
+
.add(new protobuf.Field('groupId', 2, 'string'))
|
|
128
|
+
.add(new protobuf.Field('fromUserId', 3, 'string'))
|
|
129
|
+
.add(new protobuf.Field('senderDeviceId', 4, 'string'))
|
|
130
|
+
.add(new protobuf.Field('devicePayloads', 5, 'DeviceEncryptedPayload', 'repeated'))
|
|
131
|
+
.add(new protobuf.Field('encryptionType', 6, 'EncryptionType'))
|
|
132
|
+
.add(new protobuf.Field('plaintextPayload', 7, 'string'))
|
|
133
|
+
.add(new protobuf.Field('timestamp', 8, 'int64'));
|
|
134
|
+
const GroupAckType = new protobuf.Type('GroupAck')
|
|
135
|
+
.add(new protobuf.Field('messageId', 1, 'string'))
|
|
136
|
+
.add(new protobuf.Field('groupId', 2, 'string'))
|
|
137
|
+
.add(new protobuf.Field('type', 3, 'string'));
|
|
138
|
+
const GroupCallFrameType = new protobuf.Type('GroupCallFrame')
|
|
139
|
+
.add(new protobuf.Field('type', 1, 'string'))
|
|
140
|
+
.add(new protobuf.Field('callId', 2, 'string'))
|
|
141
|
+
.add(new protobuf.Field('groupId', 3, 'string'))
|
|
142
|
+
.add(new protobuf.Field('targetUserId', 4, 'string'))
|
|
143
|
+
.add(new protobuf.Field('payload', 5, 'string'));
|
|
144
|
+
class ProtobufCodec {
|
|
145
|
+
encodeEnvelope(value) {
|
|
146
|
+
return EnvelopeType.encode(value).finish();
|
|
147
|
+
}
|
|
148
|
+
encodeAck(value) {
|
|
149
|
+
return AckType.encode(value).finish();
|
|
150
|
+
}
|
|
151
|
+
encodeCallFrame(value) {
|
|
152
|
+
return CallFrameType.encode(value).finish();
|
|
153
|
+
}
|
|
154
|
+
encodeBroadcastFrame(value) {
|
|
155
|
+
return BroadcastFrameType.encode(value).finish();
|
|
156
|
+
}
|
|
157
|
+
encodeGroupEnvelope(value) {
|
|
158
|
+
return GroupEnvelopeType.encode(value).finish();
|
|
159
|
+
}
|
|
160
|
+
encodeGroupCallFrame(value) {
|
|
161
|
+
return GroupCallFrameType.encode(value).finish();
|
|
162
|
+
}
|
|
163
|
+
encodeGroupAck(value) {
|
|
164
|
+
return GroupAckType.encode(value).finish();
|
|
165
|
+
}
|
|
166
|
+
decodeFrame(payload) {
|
|
167
|
+
const asEnvelope = this.tryDecodeEnvelope(payload);
|
|
168
|
+
if (asEnvelope) {
|
|
169
|
+
return { kind: 'envelope', data: asEnvelope };
|
|
170
|
+
}
|
|
171
|
+
// CallFrame must be checked before BroadcastNotification because protobuf
|
|
172
|
+
// field numbers overlap: CallFrame.type (1) parses into
|
|
173
|
+
// BroadcastNotification.broadcastId (1), causing call frames to be
|
|
174
|
+
// misclassified as broadcasts.
|
|
175
|
+
const asCall = this.tryDecodeCallFrame(payload);
|
|
176
|
+
if (asCall) {
|
|
177
|
+
return { kind: 'call', data: asCall };
|
|
178
|
+
}
|
|
179
|
+
// Group call frame must be checked before group message notification
|
|
180
|
+
const asGroupCall = this.tryDecodeGroupCallFrame(payload);
|
|
181
|
+
if (asGroupCall) {
|
|
182
|
+
return { kind: 'groupCall', data: asGroupCall };
|
|
183
|
+
}
|
|
184
|
+
// Group message notification (per-member stripped payload from server)
|
|
185
|
+
const asGroupMsg = this.tryDecodeGroupMessageNotification(payload);
|
|
186
|
+
if (asGroupMsg) {
|
|
187
|
+
return { kind: 'groupMessage', data: asGroupMsg };
|
|
188
|
+
}
|
|
189
|
+
// Group ack
|
|
190
|
+
const asGroupAck = this.tryDecodeGroupAck(payload);
|
|
191
|
+
if (asGroupAck) {
|
|
192
|
+
return { kind: 'groupAck', data: asGroupAck };
|
|
193
|
+
}
|
|
194
|
+
const asBroadcast = this.tryDecodeBroadcastNotification(payload);
|
|
195
|
+
if (asBroadcast) {
|
|
196
|
+
return { kind: 'broadcast', data: asBroadcast };
|
|
197
|
+
}
|
|
198
|
+
const asAck = this.tryDecodeAck(payload);
|
|
199
|
+
if (asAck) {
|
|
200
|
+
return { kind: 'ack', data: asAck };
|
|
201
|
+
}
|
|
202
|
+
const asEvent = this.tryDecodeEvent(payload);
|
|
203
|
+
if (asEvent) {
|
|
204
|
+
return { kind: 'event', data: asEvent };
|
|
205
|
+
}
|
|
206
|
+
throw new Error('Unsupported inbound protobuf frame');
|
|
207
|
+
}
|
|
208
|
+
tryDecodeEnvelope(payload) {
|
|
209
|
+
try {
|
|
210
|
+
const decoded = EnvelopeType.decode(payload);
|
|
211
|
+
if (!decoded.messageId || !decoded.toUserId) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
// Accept legacy encryptedPayload, multi-device devicePayloads, or cleartext
|
|
215
|
+
const hasLegacyPayload = decoded.encryptedPayload && decoded.encryptedPayload.length > 0;
|
|
216
|
+
const hasDevicePayloads = decoded.devicePayloads && decoded.devicePayloads.length > 0;
|
|
217
|
+
const isCleartext = decoded.encryptionType === 1 && !!decoded.plaintextPayload;
|
|
218
|
+
if (!hasLegacyPayload && !hasDevicePayloads && !isCleartext) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
const result = {
|
|
222
|
+
...decoded,
|
|
223
|
+
timestamp: Number(decoded.timestamp),
|
|
224
|
+
encryptedPayload: decoded.encryptedPayload ? new Uint8Array(decoded.encryptedPayload) : new Uint8Array(0),
|
|
225
|
+
};
|
|
226
|
+
// Normalize device payloads
|
|
227
|
+
if (hasDevicePayloads) {
|
|
228
|
+
result.devicePayloads = decoded.devicePayloads.map(dp => ({
|
|
229
|
+
deviceId: dp.deviceId,
|
|
230
|
+
encryptedPayload: new Uint8Array(dp.encryptedPayload),
|
|
231
|
+
senderPublicKey: new Uint8Array(dp.senderPublicKey),
|
|
232
|
+
}));
|
|
233
|
+
}
|
|
234
|
+
return result;
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
tryDecodeAck(payload) {
|
|
241
|
+
try {
|
|
242
|
+
const decoded = AckType.decode(payload);
|
|
243
|
+
if (!decoded.messageId || !decoded.type) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
return decoded;
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
tryDecodeEvent(payload) {
|
|
253
|
+
try {
|
|
254
|
+
const decoded = EventType.decode(payload);
|
|
255
|
+
if (!decoded.type) {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
return decoded;
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
tryDecodeCallFrame(payload) {
|
|
265
|
+
try {
|
|
266
|
+
const decoded = CallFrameType.decode(payload);
|
|
267
|
+
if (!decoded.type || !decoded.type.startsWith('CALL_')) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
return decoded;
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
tryDecodeBroadcastNotification(payload) {
|
|
277
|
+
try {
|
|
278
|
+
const decoded = BroadcastNotificationType.decode(payload);
|
|
279
|
+
if (!decoded.broadcastId || !decoded.channelId) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
...decoded,
|
|
284
|
+
timestamp: Number(decoded.timestamp),
|
|
285
|
+
encryptedPayload: decoded.encryptedPayload ? new Uint8Array(decoded.encryptedPayload) : new Uint8Array(0),
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
tryDecodeGroupMessageNotification(payload) {
|
|
293
|
+
try {
|
|
294
|
+
const decoded = GroupMessageNotificationType.decode(payload);
|
|
295
|
+
if (!decoded.messageId || !decoded.groupId) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
...decoded,
|
|
300
|
+
timestamp: Number(decoded.timestamp),
|
|
301
|
+
devicePayloads: decoded.devicePayloads?.map(dp => ({
|
|
302
|
+
deviceId: dp.deviceId,
|
|
303
|
+
encryptedPayload: new Uint8Array(dp.encryptedPayload),
|
|
304
|
+
senderPublicKey: new Uint8Array(dp.senderPublicKey),
|
|
305
|
+
})) ?? [],
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
tryDecodeGroupAck(payload) {
|
|
313
|
+
try {
|
|
314
|
+
const decoded = GroupAckType.decode(payload);
|
|
315
|
+
if (!decoded.messageId || !decoded.groupId) {
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
return decoded;
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
tryDecodeGroupCallFrame(payload) {
|
|
325
|
+
try {
|
|
326
|
+
const decoded = GroupCallFrameType.decode(payload);
|
|
327
|
+
if (!decoded.type || !decoded.type.startsWith('GROUP_CALL_')) {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
return decoded;
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
exports.ProtobufCodec = ProtobufCodec;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK version, follows semver. Bump on every release.
|
|
3
|
+
* Transmitted as X-SDK-Version header on WebSocket handshake and token exchange.
|
|
4
|
+
*
|
|
5
|
+
* Versioning rules:
|
|
6
|
+
* MAJOR, breaking wire-format or API change (e.g. new proto field required by server)
|
|
7
|
+
* MINOR, additive feature (e.g. multi-device payloads, new call event type)
|
|
8
|
+
* PATCH, bug-fix / perf improvement with no wire or API change
|
|
9
|
+
*/
|
|
10
|
+
export declare const SDK_VERSION = "0.3.0";
|
|
11
|
+
/**
|
|
12
|
+
* Binary encrypted-payload format version.
|
|
13
|
+
* Included as the first byte of every encrypted payload so receivers can
|
|
14
|
+
* select the correct decryption path if the format ever changes.
|
|
15
|
+
*/
|
|
16
|
+
export declare const PAYLOAD_FORMAT_VERSION = 1;
|
|
17
|
+
/**
|
|
18
|
+
* Protobuf wire protocol version.
|
|
19
|
+
* Increment when adding required proto fields or changing frame semantics.
|
|
20
|
+
* The server advertises its supported range via GET /api/info.
|
|
21
|
+
*/
|
|
22
|
+
export declare const PROTOCOL_VERSION = 2;
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROTOCOL_VERSION = exports.PAYLOAD_FORMAT_VERSION = exports.SDK_VERSION = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* SDK version, follows semver. Bump on every release.
|
|
6
|
+
* Transmitted as X-SDK-Version header on WebSocket handshake and token exchange.
|
|
7
|
+
*
|
|
8
|
+
* Versioning rules:
|
|
9
|
+
* MAJOR, breaking wire-format or API change (e.g. new proto field required by server)
|
|
10
|
+
* MINOR, additive feature (e.g. multi-device payloads, new call event type)
|
|
11
|
+
* PATCH, bug-fix / perf improvement with no wire or API change
|
|
12
|
+
*/
|
|
13
|
+
exports.SDK_VERSION = '0.3.0';
|
|
14
|
+
/**
|
|
15
|
+
* Binary encrypted-payload format version.
|
|
16
|
+
* Included as the first byte of every encrypted payload so receivers can
|
|
17
|
+
* select the correct decryption path if the format ever changes.
|
|
18
|
+
*/
|
|
19
|
+
exports.PAYLOAD_FORMAT_VERSION = 1;
|
|
20
|
+
/**
|
|
21
|
+
* Protobuf wire protocol version.
|
|
22
|
+
* Increment when adding required proto fields or changing frame semantics.
|
|
23
|
+
* The server advertises its supported range via GET /api/info.
|
|
24
|
+
*/
|
|
25
|
+
exports.PROTOCOL_VERSION = 2;
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@droponair/sdk-js",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "DropOnAir SDK for end-to-end encrypted messaging",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist/",
|
|
9
|
+
"README.md",
|
|
10
|
+
"CHANGELOG.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"test": "jest",
|
|
16
|
+
"smoke": "ts-node smoke/messaging-client-smoke.ts",
|
|
17
|
+
"lint": "eslint src",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"droponair",
|
|
22
|
+
"messaging",
|
|
23
|
+
"e2ee",
|
|
24
|
+
"encryption",
|
|
25
|
+
"end-to-end",
|
|
26
|
+
"sdk"
|
|
27
|
+
],
|
|
28
|
+
"author": "DropOnAir",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://droponair.com",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18.0.0"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"protobufjs": "^7.4.0",
|
|
39
|
+
"tweetnacl": "^1.0.3",
|
|
40
|
+
"tweetnacl-util": "^0.15.1"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^20.0.0",
|
|
44
|
+
"eslint": "^8.0.0",
|
|
45
|
+
"jest": "^29.0.0",
|
|
46
|
+
"ts-node": "^10.9.2",
|
|
47
|
+
"typescript": "^5.0.0"
|
|
48
|
+
}
|
|
49
|
+
}
|