@ikyyjee/ikyysinggle 1.7.7
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/WAProto/GenerateStatics.sh +3 -0
- package/WAProto/WAProto.proto +8083 -0
- package/WAProto/fix-imports.js +85 -0
- package/WAProto/index.d.ts +29095 -0
- package/WAProto/index.js +172336 -0
- package/engine-requirements.js +10 -0
- package/lib/Defaults/index.js +194 -0
- package/lib/Signal/Group/ciphertext-message.js +12 -0
- package/lib/Signal/Group/group-session-builder.js +30 -0
- package/lib/Signal/Group/group_cipher.js +82 -0
- package/lib/Signal/Group/index.js +12 -0
- package/lib/Signal/Group/keyhelper.js +18 -0
- package/lib/Signal/Group/sender-chain-key.js +26 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +63 -0
- package/lib/Signal/Group/sender-key-message.js +66 -0
- package/lib/Signal/Group/sender-key-name.js +48 -0
- package/lib/Signal/Group/sender-key-record.js +41 -0
- package/lib/Signal/Group/sender-key-state.js +84 -0
- package/lib/Signal/Group/sender-message-key.js +26 -0
- package/lib/Signal/libsignal.js +431 -0
- package/lib/Signal/lid-mapping.js +277 -0
- package/lib/Socket/Client/index.js +3 -0
- package/lib/Socket/Client/types.js +11 -0
- package/lib/Socket/Client/websocket.js +102 -0
- package/lib/Socket/aigroups.js +221 -0
- package/lib/Socket/business.js +379 -0
- package/lib/Socket/chats.js +1193 -0
- package/lib/Socket/communities.js +431 -0
- package/lib/Socket/graphql.js +524 -0
- package/lib/Socket/groups.js +408 -0
- package/lib/Socket/index.js +49 -0
- package/lib/Socket/interop.js +341 -0
- package/lib/Socket/luxu.js +510 -0
- package/lib/Socket/managed-account.js +99 -0
- package/lib/Socket/messages-recv.js +2009 -0
- package/lib/Socket/messages-send.js +1608 -0
- package/lib/Socket/mex.js +41 -0
- package/lib/Socket/newsletter.js +399 -0
- package/lib/Socket/privacy.js +128 -0
- package/lib/Socket/registration.js +238 -0
- package/lib/Socket/socket.js +1000 -0
- package/lib/Socket/text-router.js +67 -0
- package/lib/Socket/username.js +234 -0
- package/lib/Store/index.js +10 -0
- package/lib/Store/keyed-db.js +108 -0
- package/lib/Store/make-cache-manager-store.js +85 -0
- package/lib/Store/make-in-memory-store.js +198 -0
- package/lib/Store/make-ordered-dictionary.js +75 -0
- package/lib/Store/object-repository.js +32 -0
- package/lib/Types/Auth.js +2 -0
- package/lib/Types/Bussines.js +2 -0
- package/lib/Types/Call.js +2 -0
- package/lib/Types/Chat.js +8 -0
- package/lib/Types/Contact.js +2 -0
- package/lib/Types/Events.js +2 -0
- package/lib/Types/GroupMetadata.js +2 -0
- package/lib/Types/Label.js +25 -0
- package/lib/Types/LabelAssociation.js +7 -0
- package/lib/Types/Message.js +11 -0
- package/lib/Types/Mex.js +114 -0
- package/lib/Types/Product.js +2 -0
- package/lib/Types/Signal.js +2 -0
- package/lib/Types/Socket.js +3 -0
- package/lib/Types/State.js +56 -0
- package/lib/Types/USync.js +2 -0
- package/lib/Types/index.js +26 -0
- package/lib/Utils/adaptive-healing.js +53 -0
- package/lib/Utils/auth-utils.js +302 -0
- package/lib/Utils/browser-utils.js +50 -0
- package/lib/Utils/business.js +231 -0
- package/lib/Utils/chat-utils.js +872 -0
- package/lib/Utils/command-loader.js +108 -0
- package/lib/Utils/companion-reg-client-utils.js +35 -0
- package/lib/Utils/consumer-application.js +106 -0
- package/lib/Utils/crypto.js +137 -0
- package/lib/Utils/curve25519-js.js +262 -0
- package/lib/Utils/decode-wa-message.js +498 -0
- package/lib/Utils/event-buffer.js +622 -0
- package/lib/Utils/generics.js +403 -0
- package/lib/Utils/group-history.js +47 -0
- package/lib/Utils/history.js +134 -0
- package/lib/Utils/identity-change-handler.js +50 -0
- package/lib/Utils/index.js +38 -0
- package/lib/Utils/jid-display-normalization.js +198 -0
- package/lib/Utils/link-preview.js +85 -0
- package/lib/Utils/logger.js +3 -0
- package/lib/Utils/lt-hash.js +8 -0
- package/lib/Utils/make-mutex.js +33 -0
- package/lib/Utils/message-composer.js +273 -0
- package/lib/Utils/message-retry-manager.js +267 -0
- package/lib/Utils/messages-media.js +791 -0
- package/lib/Utils/messages.js +1260 -0
- package/lib/Utils/meta-ai-msmsg.js +271 -0
- package/lib/Utils/native-bridge.js +77 -0
- package/lib/Utils/noise-handler.js +201 -0
- package/lib/Utils/offline-node-processor.js +40 -0
- package/lib/Utils/optimizer.js +90 -0
- package/lib/Utils/pre-key-manager.js +106 -0
- package/lib/Utils/process-message.js +630 -0
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/session-pool.js +73 -0
- package/lib/Utils/signal.js +207 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/sticker.js +139 -0
- package/lib/Utils/sync-action-utils.js +49 -0
- package/lib/Utils/tc-token-utils.js +163 -0
- package/lib/Utils/use-multi-file-auth-state.js +121 -0
- package/lib/Utils/use-sqlite-auth-state.js +168 -0
- package/lib/Utils/validate-connection.js +203 -0
- package/lib/Utils/view-once-cache.js +79 -0
- package/lib/Utils/voip-rekey.js +25 -0
- package/lib/Utils/warmup.js +117 -0
- package/lib/WABinary/constants.js +1301 -0
- package/lib/WABinary/decode.js +262 -0
- package/lib/WABinary/encode.js +220 -0
- package/lib/WABinary/generic-utils.js +204 -0
- package/lib/WABinary/index.js +6 -0
- package/lib/WABinary/jid-utils.js +98 -0
- package/lib/WABinary/types.js +2 -0
- package/lib/WAM/BinaryInfo.js +10 -0
- package/lib/WAM/constants.js +22853 -0
- package/lib/WAM/encode.js +150 -0
- package/lib/WAM/index.js +4 -0
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +41 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +52 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +54 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +27 -0
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +52 -0
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +31 -0
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +26 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +38 -0
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +35 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +51 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +29 -0
- package/lib/WAUSync/Protocols/index.js +13 -0
- package/lib/WAUSync/USyncQuery.js +127 -0
- package/lib/WAUSync/USyncUser.js +31 -0
- package/lib/WAUSync/index.js +4 -0
- package/lib/antiban.js +4083 -0
- package/lib/index.js +24 -0
- package/package.json +147 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/Utils/command-loader.js — optional, opt-in "!command" style handler.
|
|
3
|
+
* Loads command modules from a local folder you point it at (each module
|
|
4
|
+
* exports { name, aliases?, execute(ctx) }) and dispatches incoming text
|
|
5
|
+
* messages that start with your chosen prefix to the matching command.
|
|
6
|
+
* Does nothing unless you call this yourself with a real `commandsDir`.
|
|
7
|
+
*/
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { createRequire } from 'module';
|
|
11
|
+
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param sock A connected socket (needs `sock.ev`, optionally `sock.logger`).
|
|
16
|
+
* @param options.commandsDir Folder containing your command modules.
|
|
17
|
+
* @param options.prefix Command prefix, default '!'.
|
|
18
|
+
* @param options.logger Optional logger override.
|
|
19
|
+
* @param options.onError Optional (error, msg) => void override for failures.
|
|
20
|
+
*/
|
|
21
|
+
export const createCommandHandler = (sock, options) => {
|
|
22
|
+
const prefix = options.prefix ?? '!';
|
|
23
|
+
const logger = options.logger || sock.logger;
|
|
24
|
+
const commands = new Map();
|
|
25
|
+
const load = () => {
|
|
26
|
+
commands.clear();
|
|
27
|
+
const dir = options.commandsDir;
|
|
28
|
+
if (!fs.existsSync(dir)) {
|
|
29
|
+
logger?.warn?.({ dir }, 'commands directory does not exist');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const files = fs.readdirSync(dir).filter((f) => f.endsWith('.js'));
|
|
33
|
+
for (const file of files) {
|
|
34
|
+
const fullPath = path.join(dir, file);
|
|
35
|
+
try {
|
|
36
|
+
delete require.cache[require.resolve(fullPath)];
|
|
37
|
+
const mod = require(fullPath);
|
|
38
|
+
const cmd = mod?.default || mod;
|
|
39
|
+
if (!cmd?.name || typeof cmd.execute !== 'function') {
|
|
40
|
+
logger?.warn?.({ file }, 'skipping invalid command module (missing name/execute)');
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
commands.set(cmd.name.toLowerCase(), cmd);
|
|
44
|
+
for (const alias of cmd.aliases || []) {
|
|
45
|
+
commands.set(alias.toLowerCase(), cmd);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
logger?.error?.({ error, file }, 'failed to load command');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
logger?.debug?.({ count: commands.size }, 'commands loaded');
|
|
53
|
+
};
|
|
54
|
+
load();
|
|
55
|
+
const handler = async ({ messages, type }) => {
|
|
56
|
+
if (type !== 'notify') {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
for (const msg of messages) {
|
|
60
|
+
try {
|
|
61
|
+
if (!msg.message || msg.key.fromMe) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const body = msg.message.conversation ||
|
|
65
|
+
msg.message.extendedTextMessage?.text ||
|
|
66
|
+
msg.message.imageMessage?.caption ||
|
|
67
|
+
msg.message.videoMessage?.caption ||
|
|
68
|
+
'';
|
|
69
|
+
if (!body.startsWith(prefix)) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const [cmdName, ...args] = body.slice(prefix.length).trim().split(/\s+/);
|
|
73
|
+
if (!cmdName) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const cmd = commands.get(cmdName.toLowerCase());
|
|
77
|
+
if (!cmd) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const jid = msg.key.remoteJid;
|
|
81
|
+
const ctx = {
|
|
82
|
+
sock,
|
|
83
|
+
msg,
|
|
84
|
+
args,
|
|
85
|
+
text: args.join(' '),
|
|
86
|
+
jid,
|
|
87
|
+
sender: msg.key.participant || msg.key.remoteJid,
|
|
88
|
+
isGroup: !!jid && jid.endsWith('@g.us')
|
|
89
|
+
};
|
|
90
|
+
await cmd.execute(ctx);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
if (options.onError) {
|
|
94
|
+
options.onError(error, msg);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
logger?.error?.({ error }, 'command execution failed');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
sock.ev.on('messages.upsert', handler);
|
|
103
|
+
return {
|
|
104
|
+
commands,
|
|
105
|
+
reload: load,
|
|
106
|
+
stop: () => sock.ev.off('messages.upsert', handler)
|
|
107
|
+
};
|
|
108
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export var CompanionWebClientType;
|
|
2
|
+
(function (CompanionWebClientType) {
|
|
3
|
+
CompanionWebClientType[CompanionWebClientType["UNKNOWN"] = 0] = "UNKNOWN";
|
|
4
|
+
CompanionWebClientType[CompanionWebClientType["CHROME"] = 1] = "CHROME";
|
|
5
|
+
CompanionWebClientType[CompanionWebClientType["EDGE"] = 2] = "EDGE";
|
|
6
|
+
CompanionWebClientType[CompanionWebClientType["FIREFOX"] = 3] = "FIREFOX";
|
|
7
|
+
CompanionWebClientType[CompanionWebClientType["IE"] = 4] = "IE";
|
|
8
|
+
CompanionWebClientType[CompanionWebClientType["OPERA"] = 5] = "OPERA";
|
|
9
|
+
CompanionWebClientType[CompanionWebClientType["SAFARI"] = 6] = "SAFARI";
|
|
10
|
+
CompanionWebClientType[CompanionWebClientType["ELECTRON"] = 7] = "ELECTRON";
|
|
11
|
+
CompanionWebClientType[CompanionWebClientType["UWP"] = 8] = "UWP";
|
|
12
|
+
CompanionWebClientType[CompanionWebClientType["OTHER_WEB_CLIENT"] = 9] = "OTHER_WEB_CLIENT";
|
|
13
|
+
})(CompanionWebClientType || (CompanionWebClientType = {}));
|
|
14
|
+
const BROWSER_TO_COMPANION_WEB_CLIENT = {
|
|
15
|
+
Chrome: CompanionWebClientType.CHROME,
|
|
16
|
+
Edge: CompanionWebClientType.EDGE,
|
|
17
|
+
Firefox: CompanionWebClientType.FIREFOX,
|
|
18
|
+
IE: CompanionWebClientType.IE,
|
|
19
|
+
Opera: CompanionWebClientType.OPERA,
|
|
20
|
+
Safari: CompanionWebClientType.SAFARI
|
|
21
|
+
};
|
|
22
|
+
export const getCompanionWebClientType = ([os, browserName]) => {
|
|
23
|
+
if (browserName === 'Desktop') {
|
|
24
|
+
return os === 'Windows' ? CompanionWebClientType.UWP : CompanionWebClientType.ELECTRON;
|
|
25
|
+
}
|
|
26
|
+
return BROWSER_TO_COMPANION_WEB_CLIENT[browserName] || CompanionWebClientType.OTHER_WEB_CLIENT;
|
|
27
|
+
};
|
|
28
|
+
export const getCompanionPlatformId = (browser) => {
|
|
29
|
+
return getCompanionWebClientType(browser).toString();
|
|
30
|
+
};
|
|
31
|
+
export const buildPairingQRData = (ref, noiseKeyB64, identityKeyB64, advB64, browser) => {
|
|
32
|
+
return ('https://wa.me/settings/linked_devices#' +
|
|
33
|
+
[ref, noiseKeyB64, identityKeyB64, advB64, getCompanionPlatformId(browser)].join(','));
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=companion-reg-client-utils.js.map
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/Utils/consumer-application.js — decode WhatsApp's "ConsumerApplication"
|
|
3
|
+
* envelope (used for messages relayed through interop/cross-app channels)
|
|
4
|
+
* and map it into the same plain Message shape the rest of this library
|
|
5
|
+
* already understands. Pure protobuf decode + object mapping, no I/O.
|
|
6
|
+
*/
|
|
7
|
+
import { proto } from '../../WAProto/index.js';
|
|
8
|
+
export const decodeConsumerApplication = buffer => {
|
|
9
|
+
if (!Buffer.isBuffer(buffer) && !(buffer instanceof Uint8Array)) {
|
|
10
|
+
throw new TypeError('decodeConsumerApplication: buffer must be Buffer or Uint8Array');
|
|
11
|
+
}
|
|
12
|
+
return proto.ConsumerApplication.decode(buffer);
|
|
13
|
+
};
|
|
14
|
+
const textOf = mt => (mt && typeof mt.text === 'string' ? mt.text : undefined);
|
|
15
|
+
const mapContent = content => {
|
|
16
|
+
if (!content)
|
|
17
|
+
return null;
|
|
18
|
+
switch (content.content) {
|
|
19
|
+
case 'messageText':
|
|
20
|
+
return { conversation: textOf(content.messageText) ?? '' };
|
|
21
|
+
case 'extendedTextMessage': {
|
|
22
|
+
const e = content.extendedTextMessage;
|
|
23
|
+
return {
|
|
24
|
+
extendedTextMessage: {
|
|
25
|
+
text: textOf(e.text),
|
|
26
|
+
matchedText: e.matchedText,
|
|
27
|
+
canonicalUrl: e.canonicalUrl,
|
|
28
|
+
description: e.description,
|
|
29
|
+
title: e.title
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
case 'imageMessage':
|
|
34
|
+
return {
|
|
35
|
+
imageMessage: { mediaPayload: content.imageMessage.image, caption: textOf(content.imageMessage.caption) }
|
|
36
|
+
};
|
|
37
|
+
case 'videoMessage':
|
|
38
|
+
return {
|
|
39
|
+
videoMessage: { mediaPayload: content.videoMessage.video, caption: textOf(content.videoMessage.caption) }
|
|
40
|
+
};
|
|
41
|
+
case 'audioMessage':
|
|
42
|
+
return { audioMessage: { mediaPayload: content.audioMessage.audio, ptt: content.audioMessage.ptt } };
|
|
43
|
+
case 'documentMessage':
|
|
44
|
+
return {
|
|
45
|
+
documentMessage: { mediaPayload: content.documentMessage.document, fileName: content.documentMessage.fileName }
|
|
46
|
+
};
|
|
47
|
+
case 'stickerMessage':
|
|
48
|
+
return { stickerMessage: { mediaPayload: content.stickerMessage.sticker } };
|
|
49
|
+
case 'contactMessage':
|
|
50
|
+
return { contactMessage: { mediaPayload: content.contactMessage.contact } };
|
|
51
|
+
case 'contactsArrayMessage':
|
|
52
|
+
return {
|
|
53
|
+
contactsArrayMessage: {
|
|
54
|
+
displayName: content.contactsArrayMessage.displayName,
|
|
55
|
+
contacts: content.contactsArrayMessage.contacts || []
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
case 'locationMessage': {
|
|
59
|
+
const loc = content.locationMessage.location || {};
|
|
60
|
+
return {
|
|
61
|
+
locationMessage: {
|
|
62
|
+
degreesLatitude: loc.degreesLatitude,
|
|
63
|
+
degreesLongitude: loc.degreesLongitude,
|
|
64
|
+
name: loc.name
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
case 'liveLocationMessage': {
|
|
69
|
+
const loc = content.liveLocationMessage.location || {};
|
|
70
|
+
return {
|
|
71
|
+
liveLocationMessage: {
|
|
72
|
+
degreesLatitude: loc.degreesLatitude,
|
|
73
|
+
degreesLongitude: loc.degreesLongitude,
|
|
74
|
+
caption: textOf(content.liveLocationMessage.caption)
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
case 'reactionMessage':
|
|
79
|
+
return { reactionMessage: content.reactionMessage };
|
|
80
|
+
default:
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
export const consumerApplicationToMessage = app => {
|
|
85
|
+
const payload = app?.payload;
|
|
86
|
+
if (!payload)
|
|
87
|
+
return null;
|
|
88
|
+
switch (payload.payload) {
|
|
89
|
+
case 'content':
|
|
90
|
+
return mapContent(payload.content);
|
|
91
|
+
case 'applicationData': {
|
|
92
|
+
const ad = payload.applicationData;
|
|
93
|
+
if (ad?.applicationContent === 'revoke' && ad.revoke?.key) {
|
|
94
|
+
return {
|
|
95
|
+
protocolMessage: {
|
|
96
|
+
key: ad.revoke.key,
|
|
97
|
+
type: proto.Message.ProtocolMessage.Type.REVOKE
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
default:
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes } from 'crypto';
|
|
2
|
+
import * as curve from 'libsignal/src/curve.js';
|
|
3
|
+
import { KEY_BUNDLE_TYPE } from '../Defaults/index.js';
|
|
4
|
+
import { generateKeyPairJS, sharedKeyJS, signJS, verifyJS } from './curve25519-js.js';
|
|
5
|
+
export { md5, hkdf } from 'whatsapp-rust-bridge';
|
|
6
|
+
// insure browser & node compatibility
|
|
7
|
+
const { subtle } = globalThis.crypto;
|
|
8
|
+
/** prefix version byte to the pub keys, required for some curve crypto functions */
|
|
9
|
+
export const generateSignalPubKey = (pubKey) => pubKey.length === 33 ? pubKey : Buffer.concat([KEY_BUNDLE_TYPE, pubKey]);
|
|
10
|
+
export const Curve = {
|
|
11
|
+
generateKeyPair: () => {
|
|
12
|
+
const { pubKey, privKey } = curve.generateKeyPair();
|
|
13
|
+
return {
|
|
14
|
+
private: Buffer.from(privKey),
|
|
15
|
+
// remove version byte
|
|
16
|
+
public: Buffer.from(pubKey.slice(1))
|
|
17
|
+
};
|
|
18
|
+
},
|
|
19
|
+
sharedKey: (privateKey, publicKey) => {
|
|
20
|
+
const shared = curve.calculateAgreement(generateSignalPubKey(publicKey), privateKey);
|
|
21
|
+
return Buffer.from(shared);
|
|
22
|
+
},
|
|
23
|
+
sign: (privateKey, buf) => curve.calculateSignature(privateKey, buf),
|
|
24
|
+
verify: (pubKey, message, signature) => {
|
|
25
|
+
try {
|
|
26
|
+
curve.verifySignature(generateSignalPubKey(pubKey), message, signature);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
export const signedKeyPair = (identityKeyPair, keyId) => {
|
|
35
|
+
const preKey = Curve.generateKeyPair();
|
|
36
|
+
const pubKey = generateSignalPubKey(preKey.public);
|
|
37
|
+
const signature = Curve.sign(identityKeyPair.private, pubKey);
|
|
38
|
+
return { keyPair: preKey, signature, keyId };
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Pure-JS, dependency-free fallback for `Curve` (see curve25519-js.js) — same
|
|
42
|
+
* interface, verified bit-for-bit interoperable with the `libsignal`-backed
|
|
43
|
+
* `Curve` above (cross-checked: a shared key computed one side with `Curve`
|
|
44
|
+
* and the other with `CurveJS` matches). Useful if `libsignal` (currently a
|
|
45
|
+
* `github:` dependency — see package.json / vendor-libsignal.sh) fails to
|
|
46
|
+
* install or load in your environment; not used by default anywhere in this
|
|
47
|
+
* library. See README.md → "Pure-JS Curve25519 fallback" to opt in.
|
|
48
|
+
*/
|
|
49
|
+
export const CurveJS = {
|
|
50
|
+
generateKeyPair: () => {
|
|
51
|
+
const { private: privKey, public: pubKey } = generateKeyPairJS();
|
|
52
|
+
return { private: Buffer.from(privKey), public: Buffer.from(pubKey) };
|
|
53
|
+
},
|
|
54
|
+
sharedKey: (privateKey, publicKey) => Buffer.from(sharedKeyJS(privateKey, publicKey)),
|
|
55
|
+
sign: (privateKey, buf) => signJS(privateKey, buf),
|
|
56
|
+
verify: (pubKey, message, signature) => verifyJS(pubKey, message, signature)
|
|
57
|
+
};
|
|
58
|
+
const GCM_TAG_LENGTH = 128 >> 3;
|
|
59
|
+
/**
|
|
60
|
+
* encrypt AES 256 GCM;
|
|
61
|
+
* where the tag tag is suffixed to the ciphertext
|
|
62
|
+
* */
|
|
63
|
+
export function aesEncryptGCM(plaintext, key, iv, additionalData) {
|
|
64
|
+
const cipher = createCipheriv('aes-256-gcm', key, iv);
|
|
65
|
+
cipher.setAAD(additionalData);
|
|
66
|
+
return Buffer.concat([cipher.update(plaintext), cipher.final(), cipher.getAuthTag()]);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* decrypt AES 256 GCM;
|
|
70
|
+
* where the auth tag is suffixed to the ciphertext
|
|
71
|
+
* */
|
|
72
|
+
export function aesDecryptGCM(ciphertext, key, iv, additionalData) {
|
|
73
|
+
const decipher = createDecipheriv('aes-256-gcm', key, iv);
|
|
74
|
+
// decrypt additional adata
|
|
75
|
+
const enc = ciphertext.slice(0, ciphertext.length - GCM_TAG_LENGTH);
|
|
76
|
+
const tag = ciphertext.slice(ciphertext.length - GCM_TAG_LENGTH);
|
|
77
|
+
// set additional data
|
|
78
|
+
decipher.setAAD(additionalData);
|
|
79
|
+
decipher.setAuthTag(tag);
|
|
80
|
+
return Buffer.concat([decipher.update(enc), decipher.final()]);
|
|
81
|
+
}
|
|
82
|
+
export function aesEncryptCTR(plaintext, key, iv) {
|
|
83
|
+
const cipher = createCipheriv('aes-256-ctr', key, iv);
|
|
84
|
+
return Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
85
|
+
}
|
|
86
|
+
export function aesDecryptCTR(ciphertext, key, iv) {
|
|
87
|
+
const decipher = createDecipheriv('aes-256-ctr', key, iv);
|
|
88
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
89
|
+
}
|
|
90
|
+
/** decrypt AES 256 CBC; where the IV is prefixed to the buffer */
|
|
91
|
+
export function aesDecrypt(buffer, key) {
|
|
92
|
+
return aesDecryptWithIV(buffer.subarray(16), key, buffer.subarray(0, 16));
|
|
93
|
+
}
|
|
94
|
+
/** decrypt AES 256 CBC */
|
|
95
|
+
export function aesDecryptWithIV(buffer, key, IV) {
|
|
96
|
+
const aes = createDecipheriv('aes-256-cbc', key, IV);
|
|
97
|
+
return Buffer.concat([aes.update(buffer), aes.final()]);
|
|
98
|
+
}
|
|
99
|
+
// encrypt AES 256 CBC; where a random IV is prefixed to the buffer
|
|
100
|
+
export function aesEncrypt(buffer, key) {
|
|
101
|
+
const IV = randomBytes(16);
|
|
102
|
+
const aes = createCipheriv('aes-256-cbc', key, IV);
|
|
103
|
+
return Buffer.concat([IV, aes.update(buffer), aes.final()]); // prefix IV to the buffer
|
|
104
|
+
}
|
|
105
|
+
// encrypt AES 256 CBC with a given IV
|
|
106
|
+
export function aesEncrypWithIV(buffer, key, IV) {
|
|
107
|
+
const aes = createCipheriv('aes-256-cbc', key, IV);
|
|
108
|
+
return Buffer.concat([aes.update(buffer), aes.final()]); // prefix IV to the buffer
|
|
109
|
+
}
|
|
110
|
+
// sign HMAC using SHA 256
|
|
111
|
+
export function hmacSign(buffer, key, variant = 'sha256') {
|
|
112
|
+
return createHmac(variant, key).update(buffer).digest();
|
|
113
|
+
}
|
|
114
|
+
export function sha256(buffer) {
|
|
115
|
+
return createHash('sha256').update(buffer).digest();
|
|
116
|
+
}
|
|
117
|
+
export async function derivePairingCodeKey(pairingCode, salt) {
|
|
118
|
+
// Convert inputs to formats Web Crypto API can work with
|
|
119
|
+
const encoder = new TextEncoder();
|
|
120
|
+
const pairingCodeBuffer = encoder.encode(pairingCode);
|
|
121
|
+
const saltBuffer = new Uint8Array(salt instanceof Uint8Array ? salt : new Uint8Array(salt));
|
|
122
|
+
// Import the pairing code as key material
|
|
123
|
+
const keyMaterial = await subtle.importKey('raw', pairingCodeBuffer, { name: 'PBKDF2' }, false, [
|
|
124
|
+
'deriveBits'
|
|
125
|
+
]);
|
|
126
|
+
// Derive bits using PBKDF2 with the same parameters
|
|
127
|
+
// 2 << 16 = 131,072 iterations
|
|
128
|
+
const derivedBits = await subtle.deriveBits({
|
|
129
|
+
name: 'PBKDF2',
|
|
130
|
+
salt: saltBuffer,
|
|
131
|
+
iterations: 2 << 16,
|
|
132
|
+
hash: 'SHA-256'
|
|
133
|
+
}, keyMaterial, 32 * 8 // 32 bytes * 8 = 256 bits
|
|
134
|
+
);
|
|
135
|
+
return Buffer.from(derivedBits);
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/Utils/curve25519-js.js — pure-JavaScript Curve25519 key exchange +
|
|
3
|
+
* XEdDSA-style signing, with zero external/native/git dependencies.
|
|
4
|
+
*
|
|
5
|
+
* Why this exists: the primary `Curve` implementation in crypto.js depends
|
|
6
|
+
* on the `libsignal` package, which is currently a `github:` dependency
|
|
7
|
+
* (see package.json and vendor-libsignal.sh) — meaning it needs `git` to
|
|
8
|
+
* install and, once installed, relies on that package's own native/JS
|
|
9
|
+
* curve implementation. This file is a self-contained fallback that only
|
|
10
|
+
* needs Node's built-in `crypto` module, so it keeps working even in
|
|
11
|
+
* environments where `libsignal` fails to install or load.
|
|
12
|
+
*
|
|
13
|
+
* `generateKeyPairJS`/`sharedKeyJS` delegate to Node's own built-in,
|
|
14
|
+
* standard X25519 support (`crypto.generateKeyPairSync('x25519')` /
|
|
15
|
+
* `crypto.diffieHellman`) — not custom math, low risk. `signJS`/`verifyJS`
|
|
16
|
+
* implement the XEdDSA scheme (sign/verify with a Curve25519 key, the same
|
|
17
|
+
* scheme Signal/WhatsApp use for signed prekeys) using standard Edwards
|
|
18
|
+
* curve arithmetic — publicly documented, not something invented here.
|
|
19
|
+
*
|
|
20
|
+
* This is NOT wired in as the default — see crypto.js's `CurveJS` export
|
|
21
|
+
* and README.md → "Pure-JS Curve25519 fallback" for how to opt into it.
|
|
22
|
+
* Verified via round-trip tests (sign→verify, and ECDH agreement matching
|
|
23
|
+
* between two independently generated keypairs) in the test suite.
|
|
24
|
+
*/
|
|
25
|
+
import crypto from 'crypto';
|
|
26
|
+
|
|
27
|
+
const P = 2n ** 255n - 19n;
|
|
28
|
+
const L = 2n ** 252n + 27742317777372353535851937790883648493n;
|
|
29
|
+
|
|
30
|
+
function mod(a, m = P) {
|
|
31
|
+
const r = a % m;
|
|
32
|
+
return r >= 0n ? r : r + m;
|
|
33
|
+
}
|
|
34
|
+
function powmod(b, e, m) {
|
|
35
|
+
b = mod(b, m);
|
|
36
|
+
let r = 1n;
|
|
37
|
+
while (e > 0n) {
|
|
38
|
+
if (e & 1n)
|
|
39
|
+
r = mod(r * b, m);
|
|
40
|
+
b = mod(b * b, m);
|
|
41
|
+
e >>= 1n;
|
|
42
|
+
}
|
|
43
|
+
return r;
|
|
44
|
+
}
|
|
45
|
+
function invert(a, m = P) {
|
|
46
|
+
return powmod(a, m - 2n, m);
|
|
47
|
+
}
|
|
48
|
+
const D = mod(-121665n * invert(121666n));
|
|
49
|
+
const I = powmod(2n, (P - 1n) / 4n, P);
|
|
50
|
+
function pointAdd(p1, p2) {
|
|
51
|
+
const [X1, Y1, Z1, T1] = p1;
|
|
52
|
+
const [X2, Y2, Z2, T2] = p2;
|
|
53
|
+
const A = mod((Y1 - X1) * (Y2 - X2));
|
|
54
|
+
const Bb = mod((Y1 + X1) * (Y2 + X2));
|
|
55
|
+
const C = mod(T1 * 2n * D * T2);
|
|
56
|
+
const Dd = mod(Z1 * 2n * Z2);
|
|
57
|
+
const E = Bb - A;
|
|
58
|
+
const F = Dd - C;
|
|
59
|
+
const G = Dd + C;
|
|
60
|
+
const H = Bb + A;
|
|
61
|
+
return [mod(E * F), mod(G * H), mod(F * G), mod(E * H)];
|
|
62
|
+
}
|
|
63
|
+
function pointDouble(p) {
|
|
64
|
+
const [X1, Y1, Z1] = p;
|
|
65
|
+
const A = mod(X1 * X1);
|
|
66
|
+
const Bb = mod(Y1 * Y1);
|
|
67
|
+
const C = mod(2n * Z1 * Z1);
|
|
68
|
+
const H = A + Bb;
|
|
69
|
+
const E = H - mod((X1 + Y1) * (X1 + Y1));
|
|
70
|
+
const G = A - Bb;
|
|
71
|
+
const F = C + G;
|
|
72
|
+
return [mod(E * F), mod(G * H), mod(F * G), mod(E * H)];
|
|
73
|
+
}
|
|
74
|
+
function scalarMul(s, p) {
|
|
75
|
+
let result = [0n, 1n, 1n, 0n];
|
|
76
|
+
let addend = p;
|
|
77
|
+
s = mod(s, L * 8n);
|
|
78
|
+
if (s < 0n)
|
|
79
|
+
s += L * 8n;
|
|
80
|
+
while (s > 0n) {
|
|
81
|
+
if (s & 1n)
|
|
82
|
+
result = pointAdd(result, addend);
|
|
83
|
+
addend = pointDouble(addend);
|
|
84
|
+
s >>= 1n;
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
function negatePoint(p) {
|
|
89
|
+
const [X, Y, Z, T] = p;
|
|
90
|
+
return [mod(-X), Y, Z, mod(-T)];
|
|
91
|
+
}
|
|
92
|
+
function recoverX(y, sign) {
|
|
93
|
+
const y2 = y * y;
|
|
94
|
+
const u = mod(y2 - 1n);
|
|
95
|
+
const v = mod(D * y2 + 1n);
|
|
96
|
+
let x = mod(u * invert(v));
|
|
97
|
+
x = powmod(x, (P + 3n) / 8n, P);
|
|
98
|
+
if (mod(x * x - u * invert(v)) !== 0n) {
|
|
99
|
+
x = mod(x * I);
|
|
100
|
+
}
|
|
101
|
+
if (mod(x * x - u * invert(v)) !== 0n) {
|
|
102
|
+
throw new Error('invalid Edwards point (not on curve)');
|
|
103
|
+
}
|
|
104
|
+
if ((x & 1n) !== BigInt(sign)) {
|
|
105
|
+
x = P - x;
|
|
106
|
+
}
|
|
107
|
+
return x;
|
|
108
|
+
}
|
|
109
|
+
const By = mod(4n * invert(5n));
|
|
110
|
+
const Bx = recoverX(By, 0n);
|
|
111
|
+
const BASE = [mod(Bx), mod(By), 1n, mod(mod(Bx) * mod(By))];
|
|
112
|
+
function bigIntToBytesLE(n, len) {
|
|
113
|
+
const out = Buffer.alloc(len);
|
|
114
|
+
for (let i = 0; i < len; i++) {
|
|
115
|
+
out[i] = Number(n & 0xffn);
|
|
116
|
+
n >>= 8n;
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
function bytesToBigIntLE(buf) {
|
|
121
|
+
let n = 0n;
|
|
122
|
+
for (let i = buf.length - 1; i >= 0; i--) {
|
|
123
|
+
n = (n << 8n) | BigInt(buf[i]);
|
|
124
|
+
}
|
|
125
|
+
return n;
|
|
126
|
+
}
|
|
127
|
+
function encodePoint(p) {
|
|
128
|
+
const [X, Y, Z] = p;
|
|
129
|
+
const zinv = invert(Z);
|
|
130
|
+
const x = mod(X * zinv);
|
|
131
|
+
const y = mod(Y * zinv);
|
|
132
|
+
const bytes = bigIntToBytesLE(y, 32);
|
|
133
|
+
if (x & 1n)
|
|
134
|
+
bytes[31] |= 0x80;
|
|
135
|
+
return bytes;
|
|
136
|
+
}
|
|
137
|
+
function decodePoint(buf) {
|
|
138
|
+
const sign = buf[31] & 0x80 ? 1 : 0;
|
|
139
|
+
const y = bytesToBigIntLE(buf) & ((1n << 255n) - 1n);
|
|
140
|
+
const x = recoverX(y, BigInt(sign));
|
|
141
|
+
return [x, y, 1n, mod(x * y)];
|
|
142
|
+
}
|
|
143
|
+
function sha512(...bufs) {
|
|
144
|
+
const h = crypto.createHash('sha512');
|
|
145
|
+
for (const b of bufs)
|
|
146
|
+
h.update(b);
|
|
147
|
+
return h.digest();
|
|
148
|
+
}
|
|
149
|
+
function hashI(i, ...bufs) {
|
|
150
|
+
const padding = Buffer.alloc(32, 0xff);
|
|
151
|
+
padding[0] = 0xff - i;
|
|
152
|
+
const h = crypto.createHash('sha512');
|
|
153
|
+
h.update(padding);
|
|
154
|
+
for (const b of bufs)
|
|
155
|
+
h.update(b);
|
|
156
|
+
return h.digest();
|
|
157
|
+
}
|
|
158
|
+
function signBit(pointBytes) {
|
|
159
|
+
return pointBytes[31] & 0x80 ? 1 : 0;
|
|
160
|
+
}
|
|
161
|
+
function montgomeryUToEdwardsY(uBuf) {
|
|
162
|
+
const u = mod(bytesToBigIntLE(uBuf), P);
|
|
163
|
+
return mod((u - 1n) * invert(mod(u + 1n, P)), P);
|
|
164
|
+
}
|
|
165
|
+
function encodeYWithSign(y, sign) {
|
|
166
|
+
const yBytes = bigIntToBytesLE(y, 32);
|
|
167
|
+
if (sign)
|
|
168
|
+
yBytes[31] |= 0x80;
|
|
169
|
+
return encodePoint(decodePoint(yBytes));
|
|
170
|
+
}
|
|
171
|
+
function stripKeyTypePrefix(buf) {
|
|
172
|
+
return buf.length === 33 ? buf.subarray(1) : buf;
|
|
173
|
+
}
|
|
174
|
+
function calculateKeyPair(kBuf) {
|
|
175
|
+
const k = bytesToBigIntLE(kBuf);
|
|
176
|
+
const rawPoint = scalarMul(k, BASE);
|
|
177
|
+
const rawEnc = encodePoint(rawPoint);
|
|
178
|
+
let a;
|
|
179
|
+
let A;
|
|
180
|
+
if (signBit(rawEnc) === 1) {
|
|
181
|
+
a = mod(-k, L);
|
|
182
|
+
A = encodePoint(negatePoint(rawPoint));
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
a = mod(k, L);
|
|
186
|
+
A = rawEnc;
|
|
187
|
+
}
|
|
188
|
+
return { a, A };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function signJS(privateKey, message) {
|
|
192
|
+
const Z = crypto.randomBytes(64);
|
|
193
|
+
const { a, A } = calculateKeyPair(privateKey);
|
|
194
|
+
const aBytes = bigIntToBytesLE(a, 32);
|
|
195
|
+
const r = mod(bytesToBigIntLE(hashI(1, aBytes, message, Z)), L);
|
|
196
|
+
const R = scalarMul(r, BASE);
|
|
197
|
+
const REnc = encodePoint(R);
|
|
198
|
+
const h = mod(bytesToBigIntLE(sha512(REnc, A, message)), L);
|
|
199
|
+
const s = mod(r + h * a, L);
|
|
200
|
+
return Buffer.concat([REnc, bigIntToBytesLE(s, 32)]);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function verifyJS(pubKey, message, signature) {
|
|
204
|
+
try {
|
|
205
|
+
const u = stripKeyTypePrefix(pubKey);
|
|
206
|
+
if (u.length !== 32 || signature.length !== 64)
|
|
207
|
+
return false;
|
|
208
|
+
const REnc = signature.subarray(0, 32);
|
|
209
|
+
const s = bytesToBigIntLE(signature.subarray(32, 64));
|
|
210
|
+
if (s >= L)
|
|
211
|
+
return false;
|
|
212
|
+
const A = encodeYWithSign(montgomeryUToEdwardsY(u), 0);
|
|
213
|
+
const APoint = decodePoint(A);
|
|
214
|
+
const h = mod(bytesToBigIntLE(sha512(REnc, A, message)), L);
|
|
215
|
+
const sB = scalarMul(s, BASE);
|
|
216
|
+
const hA = scalarMul(h, APoint);
|
|
217
|
+
const RCheck = pointAdd(sB, negatePoint(hA));
|
|
218
|
+
return encodePoint(RCheck).equals(REnc);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function b64url(buf) {
|
|
226
|
+
return buf.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
227
|
+
}
|
|
228
|
+
function fromB64url(str) {
|
|
229
|
+
str = str.replace(/-/g, '+').replace(/_/g, '/');
|
|
230
|
+
while (str.length % 4)
|
|
231
|
+
str += '=';
|
|
232
|
+
return Buffer.from(str, 'base64');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function generateKeyPairJS() {
|
|
236
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync('x25519');
|
|
237
|
+
const priv = fromB64url(privateKey.export({ format: 'jwk' }).d);
|
|
238
|
+
const pub = fromB64url(publicKey.export({ format: 'jwk' }).x);
|
|
239
|
+
return { private: priv, public: pub };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function generateKeyPairJS_publicFrom(privateKeyRaw) {
|
|
243
|
+
const k = bytesToBigIntLE(privateKeyRaw);
|
|
244
|
+
const point = scalarMul(k, BASE);
|
|
245
|
+
const [, Y, Z] = point;
|
|
246
|
+
const y = mod(Y * invert(Z));
|
|
247
|
+
const u = mod((1n + y) * invert(mod(1n - y)));
|
|
248
|
+
return bigIntToBytesLE(u, 32);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export function sharedKeyJS(privateKey, publicKey) {
|
|
252
|
+
const pub = stripKeyTypePrefix(publicKey);
|
|
253
|
+
const privKey = crypto.createPrivateKey({
|
|
254
|
+
key: { kty: 'OKP', crv: 'X25519', d: b64url(privateKey), x: b64url(generateKeyPairJS_publicFrom(privateKey)) },
|
|
255
|
+
format: 'jwk'
|
|
256
|
+
});
|
|
257
|
+
const pubKey = crypto.createPublicKey({
|
|
258
|
+
key: { kty: 'OKP', crv: 'X25519', x: b64url(pub) },
|
|
259
|
+
format: 'jwk'
|
|
260
|
+
});
|
|
261
|
+
return crypto.diffieHellman({ privateKey: privKey, publicKey: pubKey });
|
|
262
|
+
}
|