sauruspro-bail 5.0.0 → 5.0.2-alpha.spr.test
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/README.md +12 -9
- package/docs/CHANGELOG.md +35 -4
- package/docs/SPR.md +61 -24
- package/lib/Defaults/index.js +5 -1
- package/lib/Socket/dinonic-handler.d.ts +27 -0
- package/lib/Socket/dinonic-handler.js +882 -0
- package/lib/Socket/index.js +8 -1
- package/lib/Socket/messages-recv.js +26 -0
- package/lib/Socket/messages-send.js +25 -0
- package/lib/Utils/MessageBuilder.d.ts +215 -0
- package/lib/Utils/MessageBuilder.js +3991 -0
- package/lib/Utils/a2ui.d.ts +202 -0
- package/lib/Utils/a2ui.js +732 -0
- package/lib/Utils/airich-registry.js +3 -0
- package/lib/Utils/baileys-event-stream.js +58 -0
- package/lib/Utils/bot-signature.d.ts +22 -0
- package/lib/Utils/bot-signature.js +124 -0
- package/lib/Utils/dinonic-spr.d.ts +73 -0
- package/lib/Utils/dinonic-spr.js +739 -0
- package/lib/Utils/extras.d.ts +449 -0
- package/lib/Utils/extras.js +1377 -0
- package/lib/Utils/html-app.d.ts +39 -0
- package/lib/Utils/html-app.js +291 -0
- package/lib/Utils/index.js +14 -2
- package/lib/Utils/metaai.d.ts +438 -0
- package/lib/Utils/metaai.js +911 -0
- package/lib/Utils/modern-messages.d.ts +150 -0
- package/lib/Utils/modern-messages.js +496 -0
- package/lib/Utils/native-flow.d.ts +14 -0
- package/lib/Utils/native-flow.js +118 -0
- package/lib/Utils/newsletter-status.js +9 -53
- package/lib/Utils/payment-messages.d.ts +59 -0
- package/lib/Utils/payment-messages.js +156 -0
- package/lib/Utils/scheduled-message.d.ts +82 -0
- package/lib/Utils/scheduled-message.js +113 -0
- package/lib/Utils/status-stickers.d.ts +78 -0
- package/lib/Utils/status-stickers.js +261 -0
- package/lib/index.js +2 -2
- package/package.json +4 -4
- package/lib/Utils/dinolith-spr.d.ts +0 -26
- package/lib/Utils/dinolith-spr.js +0 -521
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import * as WAProto_1 from '../../WAProto/index.js';
|
|
2
|
+
const StatusLinkType = Object.freeze({
|
|
3
|
+
RASTERIZED_LINK_PREVIEW: 1,
|
|
4
|
+
RASTERIZED_LINK_TRUNCATED: 2,
|
|
5
|
+
RASTERIZED_LINK_FULL_URL: 3
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const STICKER_DEFAULT_AREA = Object.freeze({ x: 0.25, y: 0.4, width: 0.5, height: 0.2 });
|
|
9
|
+
|
|
10
|
+
const trimUndefined = (object) => {
|
|
11
|
+
for (const key of Object.keys(object)) {
|
|
12
|
+
if (object[key] === undefined) {
|
|
13
|
+
delete object[key];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return object;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const fraction = (value, name) => {
|
|
20
|
+
const number = Number(value);
|
|
21
|
+
if (!Number.isFinite(number) || number < 0 || number > 1) {
|
|
22
|
+
throw new TypeError(`${name} must be between 0 and 1, the client reads these as a fraction of the media`);
|
|
23
|
+
}
|
|
24
|
+
return number;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const stickerArea = ({ x, y, width, height } = STICKER_DEFAULT_AREA) => {
|
|
28
|
+
const left = fraction(x, 'x');
|
|
29
|
+
const top = fraction(y, 'y');
|
|
30
|
+
const right = fraction(left + Number(width), 'x + width');
|
|
31
|
+
const bottom = fraction(top + Number(height), 'y + height');
|
|
32
|
+
if (right <= left || bottom <= top) {
|
|
33
|
+
throw new TypeError('a sticker area needs a positive width and height');
|
|
34
|
+
}
|
|
35
|
+
return [
|
|
36
|
+
{ x: left, y: top },
|
|
37
|
+
{ x: right, y: top },
|
|
38
|
+
{ x: right, y: bottom },
|
|
39
|
+
{ x: left, y: bottom }
|
|
40
|
+
];
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const annotation = (area, fields) => ({
|
|
44
|
+
polygonVertices: Array.isArray(area) ? area : stickerArea(area),
|
|
45
|
+
...fields
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const locationSticker = ({ latitude, longitude, name, area, skipConfirmation } = {}) => {
|
|
49
|
+
const degreesLatitude = Number(latitude);
|
|
50
|
+
const degreesLongitude = Number(longitude);
|
|
51
|
+
if (!Number.isFinite(degreesLatitude) || !Number.isFinite(degreesLongitude)) {
|
|
52
|
+
throw new TypeError('locationSticker needs a numeric latitude and longitude');
|
|
53
|
+
}
|
|
54
|
+
return annotation(area, {
|
|
55
|
+
location: { degreesLatitude, degreesLongitude, ...(name ? { name } : {}) },
|
|
56
|
+
...(skipConfirmation === undefined ? {} : { shouldSkipConfirmation: !!skipConfirmation })
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const channelSticker = ({ jid, name, serverMessageId = 0, accessibilityText, area } = {}) => {
|
|
61
|
+
if (typeof jid !== 'string' || !jid.endsWith('@newsletter')) {
|
|
62
|
+
throw new TypeError('channelSticker needs the channel jid, the one ending in @newsletter');
|
|
63
|
+
}
|
|
64
|
+
return annotation(area, {
|
|
65
|
+
newsletter: {
|
|
66
|
+
newsletterJid: jid,
|
|
67
|
+
serverMessageId: Number(serverMessageId),
|
|
68
|
+
...(name ? { newsletterName: name } : {}),
|
|
69
|
+
...(accessibilityText ? { accessibilityText } : {})
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const linkSticker = ({ url, title, area, linkType = StatusLinkType.RASTERIZED_LINK_PREVIEW } = {}) => {
|
|
75
|
+
if (typeof url !== 'string' || !url) {
|
|
76
|
+
throw new TypeError('linkSticker needs a url');
|
|
77
|
+
}
|
|
78
|
+
return annotation(area, {
|
|
79
|
+
tapAction: { tapUrl: url, ...(title ? { title } : {}) },
|
|
80
|
+
statusLinkType: linkType
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const musicSticker = ({
|
|
85
|
+
songId,
|
|
86
|
+
title,
|
|
87
|
+
author,
|
|
88
|
+
mediaId,
|
|
89
|
+
artworkDirectPath,
|
|
90
|
+
artworkSha256,
|
|
91
|
+
artworkEncSha256,
|
|
92
|
+
artworkMediaKey,
|
|
93
|
+
artistAttribution,
|
|
94
|
+
countryBlocklist,
|
|
95
|
+
isExplicit,
|
|
96
|
+
startTimeMs = 0,
|
|
97
|
+
derivedStartTimeMs,
|
|
98
|
+
durationMs,
|
|
99
|
+
area
|
|
100
|
+
} = {}) => {
|
|
101
|
+
if (!songId && !mediaId) {
|
|
102
|
+
throw new TypeError('musicSticker needs at least a songId or a musicContentMediaId');
|
|
103
|
+
}
|
|
104
|
+
const bytes = value => (value === undefined ? undefined : Buffer.isBuffer(value) ? value : Buffer.from(value, 'base64'));
|
|
105
|
+
const embeddedMusic = {
|
|
106
|
+
...(songId ? { songId: String(songId) } : {}),
|
|
107
|
+
...(mediaId ? { musicContentMediaId: String(mediaId) } : {}),
|
|
108
|
+
...(title ? { title } : {}),
|
|
109
|
+
...(author ? { author } : {}),
|
|
110
|
+
...(artistAttribution ? { artistAttribution } : {}),
|
|
111
|
+
...(artworkDirectPath ? { artworkDirectPath } : {}),
|
|
112
|
+
...(isExplicit === undefined ? {} : { isExplicit: !!isExplicit }),
|
|
113
|
+
musicSongStartTimeInMs: Number(startTimeMs),
|
|
114
|
+
...(derivedStartTimeMs === undefined ? {} : { derivedContentStartTimeInMs: Number(derivedStartTimeMs) }),
|
|
115
|
+
...(durationMs === undefined ? {} : { overlapDurationInMs: Number(durationMs) })
|
|
116
|
+
};
|
|
117
|
+
for (const [key, value] of [
|
|
118
|
+
['artworkSha256', artworkSha256],
|
|
119
|
+
['artworkEncSha256', artworkEncSha256],
|
|
120
|
+
['artworkMediaKey', artworkMediaKey],
|
|
121
|
+
['countryBlocklist', countryBlocklist]
|
|
122
|
+
]) {
|
|
123
|
+
const buffer = bytes(value);
|
|
124
|
+
if (buffer) {
|
|
125
|
+
embeddedMusic[key] = buffer;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return annotation(area, { embeddedContent: { embeddedMusic } });
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const messageSticker = ({ stanzaId, message, area } = {}) => {
|
|
132
|
+
if (!message) {
|
|
133
|
+
throw new TypeError('messageSticker needs the message it embeds');
|
|
134
|
+
}
|
|
135
|
+
return annotation(area, {
|
|
136
|
+
embeddedContent: { embeddedMessage: { ...(stanzaId ? { stanzaId } : {}), message } }
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const ACTIONS = ['location', 'newsletter', 'embeddedAction', 'tapAction'];
|
|
141
|
+
|
|
142
|
+
const normalizeStickers = (stickers) => {
|
|
143
|
+
const list = Array.isArray(stickers) ? stickers : [stickers];
|
|
144
|
+
return list.filter(Boolean).map((sticker, index) => {
|
|
145
|
+
const vertices = sticker.polygonVertices;
|
|
146
|
+
if (!Array.isArray(vertices) || vertices.length !== 4) {
|
|
147
|
+
throw new TypeError(`sticker ${index} needs four polygonVertices, the client reads corner 0 and corner 2`);
|
|
148
|
+
}
|
|
149
|
+
const actions = ACTIONS.filter(name => sticker[name] !== undefined && sticker[name] !== null);
|
|
150
|
+
if (actions.length > 1) {
|
|
151
|
+
throw new TypeError(`sticker ${index} sets ${actions.join(' and ')}, but the client reads only one action per sticker`);
|
|
152
|
+
}
|
|
153
|
+
return WAProto_1.proto.InteractiveAnnotation.fromObject(sticker);
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const readStickers = (message) => {
|
|
158
|
+
const media = message?.imageMessage ?? message?.videoMessage ?? message;
|
|
159
|
+
const annotations = media?.interactiveAnnotations;
|
|
160
|
+
if (!Array.isArray(annotations) || !annotations.length) {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
return annotations.map(item => {
|
|
164
|
+
const [topLeft, , bottomRight] = item.polygonVertices ?? [];
|
|
165
|
+
const music = item.embeddedContent?.embeddedMusic;
|
|
166
|
+
return {
|
|
167
|
+
kind: item.location
|
|
168
|
+
? 'location'
|
|
169
|
+
: item.newsletter
|
|
170
|
+
? 'channel'
|
|
171
|
+
: item.tapAction
|
|
172
|
+
? 'link'
|
|
173
|
+
: music
|
|
174
|
+
? 'music'
|
|
175
|
+
: item.embeddedContent?.embeddedMessage
|
|
176
|
+
? 'message'
|
|
177
|
+
: 'unknown',
|
|
178
|
+
area: topLeft && bottomRight
|
|
179
|
+
? { x: topLeft.x, y: topLeft.y, width: bottomRight.x - topLeft.x, height: bottomRight.y - topLeft.y }
|
|
180
|
+
: undefined,
|
|
181
|
+
location: item.location ?? undefined,
|
|
182
|
+
channel: item.newsletter ?? undefined,
|
|
183
|
+
link: item.tapAction ? { url: item.tapAction.tapUrl, title: item.tapAction.title, linkType: item.statusLinkType } : undefined,
|
|
184
|
+
music: music ? { songId: music.songId, title: music.title, author: music.author } : undefined,
|
|
185
|
+
message: item.embeddedContent?.embeddedMessage ?? undefined,
|
|
186
|
+
annotation: item
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const MusicMessageStyle = Object.freeze({ UNKNOWN: 0, VINYL: 1 });
|
|
192
|
+
|
|
193
|
+
const MUSIC_ALLOWED_HOSTS = Object.freeze([
|
|
194
|
+
'.whatsapp.net',
|
|
195
|
+
'.whatsapp.com',
|
|
196
|
+
'.fbcdn.net',
|
|
197
|
+
'.facebook.com',
|
|
198
|
+
'.instagram.com',
|
|
199
|
+
'.cdninstagram.com'
|
|
200
|
+
]);
|
|
201
|
+
|
|
202
|
+
const isMusicHostAllowed = (value) => {
|
|
203
|
+
let host;
|
|
204
|
+
try {
|
|
205
|
+
host = new URL(String(value)).hostname.toLowerCase();
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
return MUSIC_ALLOWED_HOSTS.some(suffix => host.endsWith(suffix) || host === suffix.slice(1));
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const assertMusicHost = (value, label) => {
|
|
214
|
+
if (value === undefined) {
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
if (!isMusicHostAllowed(value)) {
|
|
218
|
+
throw new TypeError(
|
|
219
|
+
`${label} must be hosted on ${MUSIC_ALLOWED_HOSTS.join(', ')} — the client refuses any other host `
|
|
220
|
+
+ 'and draws nothing. Both uris come from Meta music catalog entries, so carry them over from a '
|
|
221
|
+
+ 'message you received rather than pointing at your own file'
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
return value;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const embeddedMusicOf = (options) => musicSticker(options).embeddedContent.embeddedMusic;
|
|
228
|
+
|
|
229
|
+
const buildMusicMessage = ({ songUri, artworkUri, style = MusicMessageStyle.VINYL, contextInfo, ...music } = {}) =>
|
|
230
|
+
trimUndefined({
|
|
231
|
+
embeddedMusic: embeddedMusicOf(music),
|
|
232
|
+
songUri: assertMusicHost(songUri, 'songUri'),
|
|
233
|
+
artworkUri: assertMusicHost(artworkUri, 'artworkUri'),
|
|
234
|
+
style,
|
|
235
|
+
contextInfo
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const readMusicMessage = (msg) => {
|
|
239
|
+
const message = msg?.message ?? msg;
|
|
240
|
+
const music = message?.musicMessage;
|
|
241
|
+
if (!music) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
const embedded = music.embeddedMusic ?? {};
|
|
245
|
+
return {
|
|
246
|
+
songId: embedded.songId,
|
|
247
|
+
mediaId: embedded.musicContentMediaId,
|
|
248
|
+
title: embedded.title,
|
|
249
|
+
author: embedded.author,
|
|
250
|
+
artistAttribution: embedded.artistAttribution,
|
|
251
|
+
isExplicit: embedded.isExplicit,
|
|
252
|
+
startTimeMs: embedded.musicSongStartTimeInMs,
|
|
253
|
+
durationMs: embedded.overlapDurationInMs,
|
|
254
|
+
songUri: music.songUri,
|
|
255
|
+
artworkUri: music.artworkUri,
|
|
256
|
+
style: music.style,
|
|
257
|
+
embeddedMusic: embedded
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
export { StatusLinkType, STICKER_DEFAULT_AREA, stickerArea, locationSticker, channelSticker, linkSticker, musicSticker, messageSticker, normalizeStickers, readStickers, MusicMessageStyle, MUSIC_ALLOWED_HOSTS, isMusicHostAllowed, buildMusicMessage, readMusicMessage };
|
package/lib/index.js
CHANGED
|
@@ -28,8 +28,8 @@ const info = [
|
|
|
28
28
|
{ label: "✦", value: "SPR (Selective Relay)" },
|
|
29
29
|
{ label: "✦", value: "Newsletter Status" },
|
|
30
30
|
{ label: "", value: "" },
|
|
31
|
-
{ label: "Version", value: "v5.0.
|
|
32
|
-
{ label: "Owner", value: "Saurus /
|
|
31
|
+
{ label: "Version", value: "v5.0.1" },
|
|
32
|
+
{ label: "Owner", value: "Saurus / Dinonic" },
|
|
33
33
|
{ label: "Telegram", value: "t.me/lordsaurus" },
|
|
34
34
|
{ label: "WA Owner", value: "+62 895-6390-43495" }
|
|
35
35
|
];
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sauruspro-bail",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2-alpha.spr.test",
|
|
4
4
|
"description": "Sauruspro Baileys - Custom WhatsApp Web API with SPR (Selective Relay), Newsletter Status, Rich Messages and pairing support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"baileys",
|
|
7
7
|
"whatsapp",
|
|
8
8
|
"whatsapp-baileys",
|
|
9
9
|
"Sauruspro",
|
|
10
|
-
"
|
|
10
|
+
"dinonic",
|
|
11
11
|
"newsletter-status"
|
|
12
12
|
],
|
|
13
13
|
"homepage": "https://www.npmjs.com/package/sauruspro-bail",
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
"url": "https://www.npmjs.com/package/sauruspro-bail"
|
|
17
17
|
},
|
|
18
18
|
"license": "MIT",
|
|
19
|
-
"author": "Saurus /
|
|
19
|
+
"author": "Saurus / Dinonic",
|
|
20
20
|
"contributors": [
|
|
21
21
|
"Saurus",
|
|
22
|
-
"
|
|
22
|
+
"Dinonic"
|
|
23
23
|
],
|
|
24
24
|
"type": "module",
|
|
25
25
|
"main": "lib/index.js",
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export function generateSigningKeyPair(): {
|
|
2
|
-
privateKey: Buffer;
|
|
3
|
-
publicKey: Buffer;
|
|
4
|
-
};
|
|
5
|
-
export function getMessageKey(seed: Buffer): {
|
|
6
|
-
iv: Buffer;
|
|
7
|
-
cipherKey: Buffer;
|
|
8
|
-
};
|
|
9
|
-
export function deriveReportingTag(message: any, msgId: string, remoteJid: string): Buffer;
|
|
10
|
-
export function encryptGroupMessage(plaintext: Buffer | Uint8Array, chainSeed: Buffer, privateKeyObject: any, keyId: number): Buffer;
|
|
11
|
-
export function createSKDM(keyId: number, iteration: number, chainSeed: Buffer, signingPubKey: Buffer): Buffer;
|
|
12
|
-
export function sPR(conn: any, jid: string, message: any, options?: {
|
|
13
|
-
messageId?: string;
|
|
14
|
-
additionalAttributes?: any;
|
|
15
|
-
useUserDevicesCache?: boolean;
|
|
16
|
-
useCachedGroupMetadata?: boolean;
|
|
17
|
-
statusJidList?: string[];
|
|
18
|
-
additionalNodes?: any[];
|
|
19
|
-
targetMe?: boolean;
|
|
20
|
-
mode?: "include" | "exclude";
|
|
21
|
-
target?: string[];
|
|
22
|
-
hideDecryptFail?: boolean;
|
|
23
|
-
deviceMode?: "all" | "primary" | "secondary";
|
|
24
|
-
}): Promise<string>;
|
|
25
|
-
export const selectiveRelay: typeof sPR;
|
|
26
|
-
export default sPR;
|