@mtcute/core 0.30.0 → 0.30.1
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/client.cjs +8 -0
- package/client.js +8 -0
- package/highlevel/client.d.cts +63 -1
- package/highlevel/client.d.ts +63 -1
- package/highlevel/methods/files/normalize-input-media.cjs +8 -0
- package/highlevel/methods/files/normalize-input-media.js +9 -1
- package/highlevel/methods/messages/create-rich-streaming-draft.cjs +39 -0
- package/highlevel/methods/messages/create-rich-streaming-draft.d.cts +42 -0
- package/highlevel/methods/messages/create-rich-streaming-draft.d.ts +42 -0
- package/highlevel/methods/messages/create-rich-streaming-draft.js +34 -0
- package/highlevel/methods/messages/normalize-rich-message.cjs +157 -0
- package/highlevel/methods/messages/normalize-rich-message.d.cts +10 -0
- package/highlevel/methods/messages/normalize-rich-message.d.ts +10 -0
- package/highlevel/methods/messages/normalize-rich-message.js +152 -0
- package/highlevel/methods/messages/send-rich-message.cjs +49 -0
- package/highlevel/methods/messages/send-rich-message.d.cts +38 -0
- package/highlevel/methods/messages/send-rich-message.d.ts +38 -0
- package/highlevel/methods/messages/send-rich-message.js +44 -0
- package/highlevel/methods.d.cts +3 -0
- package/highlevel/methods.d.ts +3 -0
- package/highlevel/types/bots/inline-message/factories.cjs +14 -0
- package/highlevel/types/bots/inline-message/factories.d.cts +9 -1
- package/highlevel/types/bots/inline-message/factories.d.ts +9 -1
- package/highlevel/types/bots/inline-message/factories.js +14 -0
- package/highlevel/types/bots/inline-message/types.d.cts +17 -1
- package/highlevel/types/bots/inline-message/types.d.ts +17 -1
- package/highlevel/types/media/input-media/types.d.cts +1 -1
- package/highlevel/types/media/input-media/types.d.ts +1 -1
- package/highlevel/types/messages/index.d.cts +1 -1
- package/highlevel/types/messages/index.d.ts +1 -1
- package/highlevel/types/messages/message.cjs +1 -1
- package/highlevel/types/messages/message.d.cts +1 -1
- package/highlevel/types/messages/message.d.ts +1 -1
- package/highlevel/types/messages/message.js +1 -1
- package/highlevel/types/messages/rich/index.d.cts +4 -0
- package/highlevel/types/messages/rich/index.d.ts +4 -0
- package/highlevel/types/messages/rich/inner.cjs +219 -0
- package/highlevel/types/messages/rich/inner.d.cts +127 -0
- package/highlevel/types/messages/rich/inner.d.ts +127 -0
- package/highlevel/types/messages/rich/inner.js +214 -0
- package/highlevel/types/messages/{rich-message.cjs → rich/rich-message.cjs} +6 -6
- package/highlevel/types/messages/{rich-message.d.cts → rich/rich-message.d.cts} +5 -5
- package/highlevel/types/messages/{rich-message.d.ts → rich/rich-message.d.ts} +5 -5
- package/highlevel/types/messages/{rich-message.js → rich/rich-message.js} +6 -6
- package/highlevel/types/messages/rich/types.d.cts +76 -0
- package/highlevel/types/messages/rich/types.d.ts +76 -0
- package/highlevel/updates/manager.cjs +4 -0
- package/highlevel/updates/manager.js +4 -0
- package/highlevel/utils/entities.cjs +176 -0
- package/highlevel/utils/entities.d.cts +18 -0
- package/highlevel/utils/entities.d.ts +18 -0
- package/highlevel/utils/entities.js +177 -1
- package/index.cjs +3 -1
- package/index.js +3 -1
- package/methods.cjs +4 -0
- package/methods.js +4 -0
- package/network/mtproxy/_fake-tls.cjs +169 -107
- package/network/mtproxy/_fake-tls.js +169 -107
- package/network/mtproxy/_fake-tls.test.d.cts +1 -0
- package/network/mtproxy/_fake-tls.test.d.ts +1 -0
- package/network/network-manager.cjs +1 -1
- package/network/network-manager.js +1 -1
- package/package.json +1 -1
- package/tl/api-schema.json +1 -1
- package/tl/binary/reader.cjs +115 -109
- package/tl/binary/reader.js +115 -109
- package/tl/binary/writer.cjs +243 -245
- package/tl/binary/writer.js +243 -245
- package/tl/index.d.cts +227 -216
- package/tl/index.d.ts +227 -216
- package/tl/inner-tl.cjs +3 -1
- package/tl/inner-tl.js +3 -1
- package/types/utils.d.cts +4 -0
- package/types/utils.d.ts +4 -0
- package/utils.cjs +2 -0
- package/utils.js +3 -1
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import Long from "long";
|
|
2
|
+
import { getMarkedPeerId } from "../../utils/peer-utils.js";
|
|
1
3
|
function joinTextWithEntities(parts, delim = "") {
|
|
2
4
|
const textParts = [];
|
|
3
5
|
const newEntities = [];
|
|
@@ -29,6 +31,180 @@ function joinTextWithEntities(parts, delim = "") {
|
|
|
29
31
|
entities: newEntities
|
|
30
32
|
};
|
|
31
33
|
}
|
|
34
|
+
function _entityToRichTextWrapper(entity, text) {
|
|
35
|
+
const covered = () => text.slice(entity.offset, entity.offset + entity.length);
|
|
36
|
+
switch (entity._) {
|
|
37
|
+
case "messageEntityBold":
|
|
38
|
+
return (inner) => ({ _: "textBold", text: inner });
|
|
39
|
+
case "messageEntityItalic":
|
|
40
|
+
return (inner) => ({ _: "textItalic", text: inner });
|
|
41
|
+
case "messageEntityUnderline":
|
|
42
|
+
return (inner) => ({ _: "textUnderline", text: inner });
|
|
43
|
+
case "messageEntityStrike":
|
|
44
|
+
return (inner) => ({ _: "textStrike", text: inner });
|
|
45
|
+
case "messageEntityCode":
|
|
46
|
+
case "messageEntityPre":
|
|
47
|
+
return (inner) => ({ _: "textFixed", text: inner });
|
|
48
|
+
case "messageEntitySpoiler":
|
|
49
|
+
return (inner) => ({ _: "textSpoiler", text: inner });
|
|
50
|
+
case "messageEntityMention":
|
|
51
|
+
return (inner) => ({ _: "textMention", text: inner });
|
|
52
|
+
case "messageEntityHashtag":
|
|
53
|
+
return (inner) => ({ _: "textHashtag", text: inner });
|
|
54
|
+
case "messageEntityCashtag":
|
|
55
|
+
return (inner) => ({ _: "textCashtag", text: inner });
|
|
56
|
+
case "messageEntityBotCommand":
|
|
57
|
+
return (inner) => ({ _: "textBotCommand", text: inner });
|
|
58
|
+
case "messageEntityBankCard":
|
|
59
|
+
return (inner) => ({ _: "textBankCard", text: inner });
|
|
60
|
+
case "messageEntityUrl":
|
|
61
|
+
return (inner) => ({ _: "textUrl", text: inner, url: covered(), webpageId: Long.ZERO });
|
|
62
|
+
case "messageEntityTextUrl":
|
|
63
|
+
return (inner) => ({ _: "textUrl", text: inner, url: entity.url, webpageId: Long.ZERO });
|
|
64
|
+
case "messageEntityEmail":
|
|
65
|
+
return (inner) => ({ _: "textEmail", text: inner, email: covered() });
|
|
66
|
+
case "messageEntityPhone":
|
|
67
|
+
return (inner) => ({ _: "textPhone", text: inner, phone: covered() });
|
|
68
|
+
case "messageEntityMentionName":
|
|
69
|
+
return (inner) => ({ _: "textMentionName", text: inner, userId: entity.userId });
|
|
70
|
+
case "inputMessageEntityMentionName":
|
|
71
|
+
return (inner) => ({ _: "textMentionName", text: inner, userId: getMarkedPeerId(entity.userId) });
|
|
72
|
+
case "messageEntityCustomEmoji":
|
|
73
|
+
return () => ({ _: "textCustomEmoji", documentId: entity.documentId, alt: covered() });
|
|
74
|
+
case "messageEntityFormattedDate":
|
|
75
|
+
return (inner) => ({
|
|
76
|
+
_: "textDate",
|
|
77
|
+
text: inner,
|
|
78
|
+
date: entity.date,
|
|
79
|
+
relative: entity.relative,
|
|
80
|
+
shortTime: entity.shortTime,
|
|
81
|
+
longTime: entity.longTime,
|
|
82
|
+
shortDate: entity.shortDate,
|
|
83
|
+
longDate: entity.longDate,
|
|
84
|
+
dayOfWeek: entity.dayOfWeek
|
|
85
|
+
});
|
|
86
|
+
default:
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function textWithEntitiesToRichText(input) {
|
|
91
|
+
const { text, entities } = input;
|
|
92
|
+
if (!text) return { _: "textEmpty" };
|
|
93
|
+
if (!entities?.length) return { _: "textPlain", text };
|
|
94
|
+
const bounds = /* @__PURE__ */ new Set([0, text.length]);
|
|
95
|
+
for (const e of entities) {
|
|
96
|
+
bounds.add(e.offset);
|
|
97
|
+
bounds.add(e.offset + e.length);
|
|
98
|
+
}
|
|
99
|
+
const sorted = [...bounds].filter((b) => b >= 0 && b <= text.length).sort((a, b) => a - b);
|
|
100
|
+
const segments = [];
|
|
101
|
+
for (let i = 0; i < sorted.length - 1; i++) {
|
|
102
|
+
const start = sorted[i];
|
|
103
|
+
const end = sorted[i + 1];
|
|
104
|
+
if (start === end) continue;
|
|
105
|
+
let node = { _: "textPlain", text: text.slice(start, end) };
|
|
106
|
+
const active = entities.filter((e) => e.offset <= start && e.offset + e.length >= end).sort((a, b) => a.length - b.length);
|
|
107
|
+
for (const e of active) {
|
|
108
|
+
const wrap = _entityToRichTextWrapper(e, text);
|
|
109
|
+
if (wrap) node = wrap(node);
|
|
110
|
+
}
|
|
111
|
+
segments.push(node);
|
|
112
|
+
}
|
|
113
|
+
if (segments.length === 0) return { _: "textEmpty" };
|
|
114
|
+
if (segments.length === 1) return segments[0];
|
|
115
|
+
return { _: "textConcat", texts: segments };
|
|
116
|
+
}
|
|
117
|
+
function _richTextNodeToEntity(node, offset, length) {
|
|
118
|
+
switch (node._) {
|
|
119
|
+
case "textBold":
|
|
120
|
+
return { _: "messageEntityBold", offset, length };
|
|
121
|
+
case "textItalic":
|
|
122
|
+
return { _: "messageEntityItalic", offset, length };
|
|
123
|
+
case "textUnderline":
|
|
124
|
+
return { _: "messageEntityUnderline", offset, length };
|
|
125
|
+
case "textStrike":
|
|
126
|
+
return { _: "messageEntityStrike", offset, length };
|
|
127
|
+
case "textFixed":
|
|
128
|
+
return { _: "messageEntityCode", offset, length };
|
|
129
|
+
case "textSpoiler":
|
|
130
|
+
return { _: "messageEntitySpoiler", offset, length };
|
|
131
|
+
case "textMention":
|
|
132
|
+
return { _: "messageEntityMention", offset, length };
|
|
133
|
+
case "textHashtag":
|
|
134
|
+
return { _: "messageEntityHashtag", offset, length };
|
|
135
|
+
case "textCashtag":
|
|
136
|
+
return { _: "messageEntityCashtag", offset, length };
|
|
137
|
+
case "textBotCommand":
|
|
138
|
+
return { _: "messageEntityBotCommand", offset, length };
|
|
139
|
+
case "textBankCard":
|
|
140
|
+
return { _: "messageEntityBankCard", offset, length };
|
|
141
|
+
case "textUrl":
|
|
142
|
+
return { _: "messageEntityTextUrl", offset, length, url: node.url };
|
|
143
|
+
case "textEmail":
|
|
144
|
+
return { _: "messageEntityEmail", offset, length };
|
|
145
|
+
case "textPhone":
|
|
146
|
+
return { _: "messageEntityPhone", offset, length };
|
|
147
|
+
case "textMentionName":
|
|
148
|
+
return { _: "messageEntityMentionName", offset, length, userId: node.userId };
|
|
149
|
+
case "textDate":
|
|
150
|
+
return {
|
|
151
|
+
_: "messageEntityFormattedDate",
|
|
152
|
+
offset,
|
|
153
|
+
length,
|
|
154
|
+
date: node.date,
|
|
155
|
+
relative: node.relative,
|
|
156
|
+
shortTime: node.shortTime,
|
|
157
|
+
longTime: node.longTime,
|
|
158
|
+
shortDate: node.shortDate,
|
|
159
|
+
longDate: node.longDate,
|
|
160
|
+
dayOfWeek: node.dayOfWeek
|
|
161
|
+
};
|
|
162
|
+
default:
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function richTextToTextWithEntities(rich) {
|
|
167
|
+
const entities = [];
|
|
168
|
+
let text = "";
|
|
169
|
+
const walk = (node) => {
|
|
170
|
+
switch (node._) {
|
|
171
|
+
case "textEmpty":
|
|
172
|
+
return;
|
|
173
|
+
case "textPlain":
|
|
174
|
+
text += node.text;
|
|
175
|
+
return;
|
|
176
|
+
case "textConcat":
|
|
177
|
+
for (const t of node.texts) walk(t);
|
|
178
|
+
return;
|
|
179
|
+
case "textImage":
|
|
180
|
+
return;
|
|
181
|
+
case "textMath":
|
|
182
|
+
text += node.source;
|
|
183
|
+
return;
|
|
184
|
+
case "textCustomEmoji": {
|
|
185
|
+
const start = text.length;
|
|
186
|
+
text += node.alt;
|
|
187
|
+
entities.push({
|
|
188
|
+
_: "messageEntityCustomEmoji",
|
|
189
|
+
offset: start,
|
|
190
|
+
length: text.length - start,
|
|
191
|
+
documentId: node.documentId
|
|
192
|
+
});
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
default: {
|
|
196
|
+
const start = text.length;
|
|
197
|
+
walk(node.text);
|
|
198
|
+
const entity = _richTextNodeToEntity(node, start, text.length - start);
|
|
199
|
+
if (entity) entities.push(entity);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
walk(rich);
|
|
204
|
+
return { text, entities };
|
|
205
|
+
}
|
|
32
206
|
export {
|
|
33
|
-
joinTextWithEntities
|
|
207
|
+
joinTextWithEntities,
|
|
208
|
+
richTextToTextWithEntities,
|
|
209
|
+
textWithEntitiesToRichText
|
|
34
210
|
};
|
package/index.cjs
CHANGED
|
@@ -56,7 +56,8 @@ const messageReactions = require("./highlevel/types/messages/message-reactions.c
|
|
|
56
56
|
const messageReplies = require("./highlevel/types/messages/message-replies.cjs");
|
|
57
57
|
const message = require("./highlevel/types/messages/message.cjs");
|
|
58
58
|
const repliedMessage = require("./highlevel/types/messages/replied-message.cjs");
|
|
59
|
-
const richMessage = require("./highlevel/types/messages/rich-message.cjs");
|
|
59
|
+
const richMessage = require("./highlevel/types/messages/rich/rich-message.cjs");
|
|
60
|
+
const inner$1 = require("./highlevel/types/messages/rich/inner.cjs");
|
|
60
61
|
const searchFilters = require("./highlevel/types/messages/search-filters.cjs");
|
|
61
62
|
const suggestedPost = require("./highlevel/types/messages/suggested-post.cjs");
|
|
62
63
|
const collectibleInfo = require("./highlevel/types/misc/collectible-info.cjs");
|
|
@@ -227,6 +228,7 @@ exports.MessageRepliesInfo = messageReplies.MessageRepliesInfo;
|
|
|
227
228
|
exports.Message = message.Message;
|
|
228
229
|
exports.RepliedMessageInfo = repliedMessage.RepliedMessageInfo;
|
|
229
230
|
exports.RichMessage = richMessage.RichMessage;
|
|
231
|
+
exports.Rich = inner$1;
|
|
230
232
|
exports.SearchFilters = searchFilters.SearchFilters;
|
|
231
233
|
exports.SuggestedPostInfo = suggestedPost.SuggestedPostInfo;
|
|
232
234
|
exports.CollectibleInfo = collectibleInfo.CollectibleInfo;
|
package/index.js
CHANGED
|
@@ -49,7 +49,8 @@ import { MessageReactions } from "./highlevel/types/messages/message-reactions.j
|
|
|
49
49
|
import { MessageRepliesInfo } from "./highlevel/types/messages/message-replies.js";
|
|
50
50
|
import { Message } from "./highlevel/types/messages/message.js";
|
|
51
51
|
import { RepliedMessageInfo } from "./highlevel/types/messages/replied-message.js";
|
|
52
|
-
import { RichMessage } from "./highlevel/types/messages/rich-message.js";
|
|
52
|
+
import { RichMessage } from "./highlevel/types/messages/rich/rich-message.js";
|
|
53
|
+
import * as inner$1 from "./highlevel/types/messages/rich/inner.js";
|
|
53
54
|
import { SearchFilters } from "./highlevel/types/messages/search-filters.js";
|
|
54
55
|
import { SuggestedPostInfo } from "./highlevel/types/messages/suggested-post.js";
|
|
55
56
|
import { CollectibleInfo } from "./highlevel/types/misc/collectible-info.js";
|
|
@@ -272,6 +273,7 @@ export {
|
|
|
272
273
|
RawUpdateInfo,
|
|
273
274
|
ReactionCount,
|
|
274
275
|
RepliedMessageInfo,
|
|
276
|
+
inner$1 as Rich,
|
|
275
277
|
RichMessage,
|
|
276
278
|
SavedStarGift,
|
|
277
279
|
SearchFilters,
|
package/methods.cjs
CHANGED
|
@@ -157,6 +157,7 @@ const iterInviteLinks = require("./highlevel/methods/invite-links/iter-invite-li
|
|
|
157
157
|
const revokeInviteLink = require("./highlevel/methods/invite-links/revoke-invite-link.cjs");
|
|
158
158
|
const appendTodoList = require("./highlevel/methods/messages/append-todo-list.cjs");
|
|
159
159
|
const closePoll = require("./highlevel/methods/messages/close-poll.cjs");
|
|
160
|
+
const createRichStreamingDraft = require("./highlevel/methods/messages/create-rich-streaming-draft.cjs");
|
|
160
161
|
const createStreamingDraft = require("./highlevel/methods/messages/create-streaming-draft.cjs");
|
|
161
162
|
const deleteMessages = require("./highlevel/methods/messages/delete-messages.cjs");
|
|
162
163
|
const deleteScheduledMessages = require("./highlevel/methods/messages/delete-scheduled-messages.cjs");
|
|
@@ -199,6 +200,7 @@ const sendPaidReaction = require("./highlevel/methods/messages/send-paid-reactio
|
|
|
199
200
|
const sendQuote = require("./highlevel/methods/messages/send-quote.cjs");
|
|
200
201
|
const sendReaction = require("./highlevel/methods/messages/send-reaction.cjs");
|
|
201
202
|
const sendReply = require("./highlevel/methods/messages/send-reply.cjs");
|
|
203
|
+
const sendRichMessage = require("./highlevel/methods/messages/send-rich-message.cjs");
|
|
202
204
|
const sendScheduled = require("./highlevel/methods/messages/send-scheduled.cjs");
|
|
203
205
|
const sendText = require("./highlevel/methods/messages/send-text.cjs");
|
|
204
206
|
const sendTyping = require("./highlevel/methods/messages/send-typing.cjs");
|
|
@@ -444,6 +446,7 @@ exports.iterInviteLinks = iterInviteLinks.iterInviteLinks;
|
|
|
444
446
|
exports.revokeInviteLink = revokeInviteLink.revokeInviteLink;
|
|
445
447
|
exports.appendTodoList = appendTodoList.appendTodoList;
|
|
446
448
|
exports.closePoll = closePoll.closePoll;
|
|
449
|
+
exports.createRichStreamingDraft = createRichStreamingDraft.createRichStreamingDraft;
|
|
447
450
|
exports.createStreamingDraft = createStreamingDraft.createStreamingDraft;
|
|
448
451
|
exports.deleteMessages = deleteMessages.deleteMessages;
|
|
449
452
|
exports.deleteMessagesById = deleteMessages.deleteMessagesById;
|
|
@@ -498,6 +501,7 @@ exports.sendReaction = sendReaction.sendReaction;
|
|
|
498
501
|
exports.replyMedia = sendReply.replyMedia;
|
|
499
502
|
exports.replyMediaGroup = sendReply.replyMediaGroup;
|
|
500
503
|
exports.replyText = sendReply.replyText;
|
|
504
|
+
exports.sendRichMessage = sendRichMessage.sendRichMessage;
|
|
501
505
|
exports.sendScheduled = sendScheduled.sendScheduled;
|
|
502
506
|
exports.sendText = sendText.sendText;
|
|
503
507
|
exports.sendTyping = sendTyping.sendTyping;
|
package/methods.js
CHANGED
|
@@ -150,6 +150,7 @@ import { iterInviteLinks } from "./highlevel/methods/invite-links/iter-invite-li
|
|
|
150
150
|
import { revokeInviteLink } from "./highlevel/methods/invite-links/revoke-invite-link.js";
|
|
151
151
|
import { appendTodoList } from "./highlevel/methods/messages/append-todo-list.js";
|
|
152
152
|
import { closePoll } from "./highlevel/methods/messages/close-poll.js";
|
|
153
|
+
import { createRichStreamingDraft } from "./highlevel/methods/messages/create-rich-streaming-draft.js";
|
|
153
154
|
import { createStreamingDraft } from "./highlevel/methods/messages/create-streaming-draft.js";
|
|
154
155
|
import { deleteMessages, deleteMessagesById } from "./highlevel/methods/messages/delete-messages.js";
|
|
155
156
|
import { deleteScheduledMessages } from "./highlevel/methods/messages/delete-scheduled-messages.js";
|
|
@@ -192,6 +193,7 @@ import { sendPaidReaction } from "./highlevel/methods/messages/send-paid-reactio
|
|
|
192
193
|
import { quoteWithMedia, quoteWithMediaGroup, quoteWithText } from "./highlevel/methods/messages/send-quote.js";
|
|
193
194
|
import { sendReaction } from "./highlevel/methods/messages/send-reaction.js";
|
|
194
195
|
import { replyMedia, replyMediaGroup, replyText } from "./highlevel/methods/messages/send-reply.js";
|
|
196
|
+
import { sendRichMessage } from "./highlevel/methods/messages/send-rich-message.js";
|
|
195
197
|
import { sendScheduled } from "./highlevel/methods/messages/send-scheduled.js";
|
|
196
198
|
import { sendText } from "./highlevel/methods/messages/send-text.js";
|
|
197
199
|
import { sendTyping } from "./highlevel/methods/messages/send-typing.js";
|
|
@@ -320,6 +322,7 @@ export {
|
|
|
320
322
|
createForumTopic,
|
|
321
323
|
createGroup,
|
|
322
324
|
createInviteLink,
|
|
325
|
+
createRichStreamingDraft,
|
|
323
326
|
createStickerSet,
|
|
324
327
|
createStreamingDraft,
|
|
325
328
|
createSupergroup,
|
|
@@ -520,6 +523,7 @@ export {
|
|
|
520
523
|
sendPaidReaction,
|
|
521
524
|
sendReaction,
|
|
522
525
|
sendRecoveryCode,
|
|
526
|
+
sendRichMessage,
|
|
523
527
|
sendScheduled,
|
|
524
528
|
sendStarGift,
|
|
525
529
|
sendStarGiftOffer,
|
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
8
8
|
const io = require("@fuman/io");
|
|
9
9
|
const utils = require("@fuman/utils");
|
|
10
10
|
const MAX_TLS_PACKET_LENGTH = 2878;
|
|
11
|
+
const MAX_TLS_HELLO_SIZE = 4096;
|
|
11
12
|
const KEY_MOD = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEDn;
|
|
12
13
|
const QUAD_RES_MOD = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEDn;
|
|
13
14
|
const QUAD_RES_POW = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6n;
|
|
@@ -34,7 +35,11 @@ function _isQuadraticResidue(a) {
|
|
|
34
35
|
return r === 1n;
|
|
35
36
|
}
|
|
36
37
|
function executeTlsOperations(h) {
|
|
37
|
-
h.string([22, 3, 1
|
|
38
|
+
h.string([22, 3, 1]);
|
|
39
|
+
h.beginScope();
|
|
40
|
+
h.string([1, 0]);
|
|
41
|
+
h.beginScope();
|
|
42
|
+
h.string([3, 3]);
|
|
38
43
|
h.zero(32);
|
|
39
44
|
h.string([32]);
|
|
40
45
|
h.random(32);
|
|
@@ -72,67 +77,34 @@ function executeTlsOperations(h) {
|
|
|
72
77
|
0,
|
|
73
78
|
53,
|
|
74
79
|
1,
|
|
75
|
-
0
|
|
76
|
-
1,
|
|
77
|
-
147
|
|
80
|
+
0
|
|
78
81
|
]);
|
|
79
|
-
h.grease(2);
|
|
80
|
-
h.string([0, 0, 0, 0]);
|
|
81
|
-
h.beginScope();
|
|
82
82
|
h.beginScope();
|
|
83
|
-
h.
|
|
84
|
-
h.
|
|
85
|
-
h.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
0,
|
|
109
|
-
0,
|
|
110
|
-
16,
|
|
111
|
-
0,
|
|
112
|
-
14,
|
|
113
|
-
0,
|
|
114
|
-
12,
|
|
115
|
-
2,
|
|
116
|
-
104,
|
|
117
|
-
50,
|
|
118
|
-
8,
|
|
119
|
-
104,
|
|
120
|
-
116,
|
|
121
|
-
116,
|
|
122
|
-
112,
|
|
123
|
-
47,
|
|
124
|
-
49,
|
|
125
|
-
46,
|
|
126
|
-
49,
|
|
127
|
-
0,
|
|
128
|
-
5,
|
|
129
|
-
0,
|
|
130
|
-
5,
|
|
131
|
-
1,
|
|
132
|
-
0,
|
|
133
|
-
0,
|
|
134
|
-
0,
|
|
135
|
-
0,
|
|
83
|
+
h.grease(2);
|
|
84
|
+
h.string([0, 0]);
|
|
85
|
+
h.permutation([
|
|
86
|
+
(w) => {
|
|
87
|
+
w.string([0, 0]);
|
|
88
|
+
w.beginScope();
|
|
89
|
+
w.beginScope();
|
|
90
|
+
w.string([0]);
|
|
91
|
+
w.beginScope();
|
|
92
|
+
w.domain();
|
|
93
|
+
w.endScope();
|
|
94
|
+
w.endScope();
|
|
95
|
+
w.endScope();
|
|
96
|
+
},
|
|
97
|
+
(w) => w.string([0, 5, 0, 5, 1, 0, 0, 0, 0]),
|
|
98
|
+
// status_request
|
|
99
|
+
(w) => {
|
|
100
|
+
w.string([0, 10, 0, 12, 0, 10]);
|
|
101
|
+
w.grease(4);
|
|
102
|
+
w.string([17, 236, 0, 29, 0, 23, 0, 24]);
|
|
103
|
+
},
|
|
104
|
+
(w) => w.string([0, 11, 0, 2, 1, 0]),
|
|
105
|
+
// ec_point_formats
|
|
106
|
+
(w) => w.string([
|
|
107
|
+
// signature_algorithms
|
|
136
108
|
0,
|
|
137
109
|
13,
|
|
138
110
|
0,
|
|
@@ -154,27 +126,76 @@ function executeTlsOperations(h) {
|
|
|
154
126
|
8,
|
|
155
127
|
6,
|
|
156
128
|
6,
|
|
157
|
-
1
|
|
129
|
+
1
|
|
130
|
+
]),
|
|
131
|
+
(w) => w.string([
|
|
132
|
+
// application_layer_protocol_negotiation (ALPN)
|
|
158
133
|
0,
|
|
159
|
-
|
|
160
|
-
0,
|
|
161
|
-
0,
|
|
162
|
-
0,
|
|
163
|
-
51,
|
|
134
|
+
16,
|
|
164
135
|
0,
|
|
165
|
-
|
|
136
|
+
14,
|
|
166
137
|
0,
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
138
|
+
12,
|
|
139
|
+
2,
|
|
140
|
+
104,
|
|
141
|
+
50,
|
|
142
|
+
8,
|
|
143
|
+
104,
|
|
144
|
+
116,
|
|
145
|
+
116,
|
|
146
|
+
112,
|
|
147
|
+
47,
|
|
148
|
+
49,
|
|
149
|
+
46,
|
|
150
|
+
49
|
|
151
|
+
]),
|
|
152
|
+
(w) => w.string([0, 18, 0, 0]),
|
|
153
|
+
// signed_certificate_timestamp
|
|
154
|
+
(w) => w.string([0, 23, 0, 0]),
|
|
155
|
+
// extended_master_secret
|
|
156
|
+
(w) => w.string([0, 27, 0, 3, 2, 0, 2]),
|
|
157
|
+
// compress_certificate
|
|
158
|
+
(w) => w.string([0, 35, 0, 0]),
|
|
159
|
+
// session_ticket
|
|
160
|
+
(w) => {
|
|
161
|
+
w.string([0, 43, 0, 7, 6]);
|
|
162
|
+
w.grease(6);
|
|
163
|
+
w.string([3, 4, 3, 3]);
|
|
164
|
+
},
|
|
165
|
+
(w) => w.string([0, 45, 0, 2, 1, 1]),
|
|
166
|
+
// psk_key_exchange_modes
|
|
167
|
+
(w) => {
|
|
168
|
+
w.string([0, 51, 4, 239, 4, 237]);
|
|
169
|
+
w.grease(4);
|
|
170
|
+
w.string([0, 1, 0, 17, 236, 4, 192]);
|
|
171
|
+
w.mlKem768Key();
|
|
172
|
+
w.key();
|
|
173
|
+
w.string([0, 29, 0, 32]);
|
|
174
|
+
w.key();
|
|
175
|
+
},
|
|
176
|
+
(w) => w.string([68, 205, 0, 5, 0, 3, 2, 104, 50]),
|
|
177
|
+
// application_settings (ALPS)
|
|
178
|
+
(w) => {
|
|
179
|
+
w.string([254, 13]);
|
|
180
|
+
w.beginScope();
|
|
181
|
+
w.string([0, 0, 1, 0, 1]);
|
|
182
|
+
w.random(1);
|
|
183
|
+
w.string([0, 32]);
|
|
184
|
+
w.random(32);
|
|
185
|
+
w.beginScope();
|
|
186
|
+
w.echPayload();
|
|
187
|
+
w.endScope();
|
|
188
|
+
w.endScope();
|
|
189
|
+
},
|
|
190
|
+
(w) => w.string([255, 1, 0, 1, 0])
|
|
191
|
+
// renegotiation_info
|
|
192
|
+
]);
|
|
176
193
|
h.grease(3);
|
|
177
|
-
h.string([0, 1, 0
|
|
194
|
+
h.string([0, 1, 0]);
|
|
195
|
+
h.padding();
|
|
196
|
+
h.endScope();
|
|
197
|
+
h.endScope();
|
|
198
|
+
h.endScope();
|
|
178
199
|
}
|
|
179
200
|
function initGrease(crypto, size) {
|
|
180
201
|
const buf = crypto.randomBytes(size);
|
|
@@ -189,12 +210,12 @@ function initGrease(crypto, size) {
|
|
|
189
210
|
return buf;
|
|
190
211
|
}
|
|
191
212
|
class TlsHelloWriter {
|
|
192
|
-
constructor(crypto,
|
|
213
|
+
constructor(crypto, domain, grease) {
|
|
193
214
|
this.crypto = crypto;
|
|
194
215
|
this._domain = domain;
|
|
195
|
-
this.buf = utils.u8.alloc(
|
|
216
|
+
this.buf = utils.u8.alloc(MAX_TLS_HELLO_SIZE);
|
|
196
217
|
this.dv = utils.typed.toDataView(this.buf);
|
|
197
|
-
this._grease = initGrease(this.crypto, 7);
|
|
218
|
+
this._grease = grease ?? initGrease(this.crypto, 7);
|
|
198
219
|
}
|
|
199
220
|
buf;
|
|
200
221
|
dv;
|
|
@@ -235,6 +256,24 @@ class TlsHelloWriter {
|
|
|
235
256
|
}
|
|
236
257
|
}
|
|
237
258
|
}
|
|
259
|
+
// fake X25519MLKEM768 hybrid keyshare's ml-kem-768 part: 384 coefficients
|
|
260
|
+
// (mod 3329) packed 3 bytes per 2 coefficients, followed by 32 random bytes
|
|
261
|
+
mlKem768Key() {
|
|
262
|
+
const rnd = this.crypto.randomBytes(384 * 8);
|
|
263
|
+
const dv = utils.typed.toDataView(rnd);
|
|
264
|
+
for (let i = 0; i < 384; i++) {
|
|
265
|
+
const a = dv.getUint32(i * 8, true) % 3329;
|
|
266
|
+
const b = dv.getUint32(i * 8 + 4, true) % 3329;
|
|
267
|
+
this.buf[this.pos++] = a & 255;
|
|
268
|
+
this.buf[this.pos++] = (a >> 8) + ((b & 15) << 4);
|
|
269
|
+
this.buf[this.pos++] = b >> 4;
|
|
270
|
+
}
|
|
271
|
+
this.random(32);
|
|
272
|
+
}
|
|
273
|
+
// GREASE ECH payload: random bytes of length 144/176/208/240
|
|
274
|
+
echPayload() {
|
|
275
|
+
this.random(this._randomInt(4) * 32 + 144);
|
|
276
|
+
}
|
|
238
277
|
beginScope() {
|
|
239
278
|
this._scopes.push(this.pos);
|
|
240
279
|
this.pos += 2;
|
|
@@ -244,29 +283,55 @@ class TlsHelloWriter {
|
|
|
244
283
|
if (begin === void 0) {
|
|
245
284
|
throw new Error("endScope called without beginScope");
|
|
246
285
|
}
|
|
247
|
-
|
|
248
|
-
const size = end - begin - 2;
|
|
249
|
-
this.dv.setUint16(begin, size);
|
|
286
|
+
this.dv.setUint16(begin, this.pos - begin - 2);
|
|
250
287
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
288
|
+
// render each part into its own buffer, then emit them in random order —
|
|
289
|
+
// mimics chrome's per-connection tls extension shuffling
|
|
290
|
+
permutation(parts) {
|
|
291
|
+
const rendered = parts.map((fn) => {
|
|
292
|
+
const sub = new TlsHelloWriter(this.crypto, this._domain, this._grease);
|
|
293
|
+
fn(sub);
|
|
294
|
+
return sub.buf.subarray(0, sub.pos);
|
|
295
|
+
});
|
|
296
|
+
for (let i = rendered.length - 1; i > 0; i--) {
|
|
297
|
+
const j = this._randomInt(i + 1);
|
|
298
|
+
const tmp = rendered[i];
|
|
299
|
+
rendered[i] = rendered[j];
|
|
300
|
+
rendered[j] = tmp;
|
|
301
|
+
}
|
|
302
|
+
for (const part of rendered) {
|
|
303
|
+
this.string(part);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// tls padding extension, only emitted for hellos smaller than 513 bytes
|
|
307
|
+
padding() {
|
|
308
|
+
if (this.pos >= 513) return;
|
|
309
|
+
const size = 513 - this.pos;
|
|
310
|
+
this.string([0, 21]);
|
|
254
311
|
this.beginScope();
|
|
255
|
-
this.zero(
|
|
312
|
+
this.zero(size);
|
|
256
313
|
this.endScope();
|
|
257
|
-
|
|
314
|
+
}
|
|
315
|
+
_randomInt(max) {
|
|
316
|
+
return utils.typed.toDataView(this.crypto.randomBytes(4)).getUint32(0, true) % max;
|
|
317
|
+
}
|
|
318
|
+
async finish(secret) {
|
|
319
|
+
const data = this.buf.subarray(0, this.pos);
|
|
320
|
+
const unixTime = ~~(Date.now() / 1e3);
|
|
321
|
+
const hash = await this.crypto.hmacSha256(data, secret);
|
|
258
322
|
const dv = utils.typed.toDataView(hash);
|
|
259
323
|
const old = dv.getInt32(28, true);
|
|
260
324
|
dv.setInt32(28, old ^ unixTime, true);
|
|
261
|
-
|
|
262
|
-
return
|
|
325
|
+
data.set(hash, 11);
|
|
326
|
+
return data;
|
|
263
327
|
}
|
|
264
328
|
}
|
|
265
329
|
async function generateFakeTlsHeader(domain, secret, crypto) {
|
|
266
|
-
const writer = new TlsHelloWriter(crypto,
|
|
330
|
+
const writer = new TlsHelloWriter(crypto, domain);
|
|
267
331
|
executeTlsOperations(writer);
|
|
268
332
|
return writer.finish(secret);
|
|
269
333
|
}
|
|
334
|
+
const EMPTY_BYTES = io.Bytes.from(utils.u8.empty);
|
|
270
335
|
class FakeTlsPacketCodec {
|
|
271
336
|
// protected _stream: Buffer = Buffer.alloc(0)
|
|
272
337
|
constructor(_inner) {
|
|
@@ -301,23 +366,20 @@ class FakeTlsPacketCodec {
|
|
|
301
366
|
}
|
|
302
367
|
async decode(reader, eof) {
|
|
303
368
|
if (eof) return null;
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
if (!inner) {
|
|
317
|
-
reader.rewind(5 + length);
|
|
318
|
-
return null;
|
|
369
|
+
while (reader.available >= 5) {
|
|
370
|
+
const header = reader.readSync(3);
|
|
371
|
+
if (header[0] !== 23 || header[1] !== 3 || header[2] !== 3) {
|
|
372
|
+
throw new Error("Invalid TLS header");
|
|
373
|
+
}
|
|
374
|
+
const length = io.read.uint16be(reader);
|
|
375
|
+
if (reader.available < length) {
|
|
376
|
+
reader.rewind(5);
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
const inner = await this._inner.decode(io.Bytes.from(reader.readSync(length)), eof);
|
|
380
|
+
if (inner) return inner;
|
|
319
381
|
}
|
|
320
|
-
return
|
|
382
|
+
return this._inner.decode(EMPTY_BYTES, eof);
|
|
321
383
|
}
|
|
322
384
|
reset() {
|
|
323
385
|
this._isFirstTls = true;
|