@xbibzlibrary/telebibz 0.1.9 → 0.1.11
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.id.md +3 -12
- package/README.md +28 -8
- package/README.zh-CN.md +2 -11
- package/assets/readme-preview.html +2 -2
- package/dist/src/branding/terminal.js +1 -1
- package/dist/src/branding/terminal.js.map +1 -1
- package/dist/src/core/bot.d.ts +11 -4
- package/dist/src/core/bot.d.ts.map +1 -1
- package/dist/src/core/bot.js +40 -19
- package/dist/src/core/bot.js.map +1 -1
- package/dist/src/index.d.ts +0 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +0 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/observability/logger.d.ts +6 -0
- package/dist/src/observability/logger.d.ts.map +1 -1
- package/dist/src/observability/logger.js +56 -11
- package/dist/src/observability/logger.js.map +1 -1
- package/dist/src/state/conversation.d.ts +10 -1
- package/dist/src/state/conversation.d.ts.map +1 -1
- package/dist/src/state/conversation.js +20 -2
- package/dist/src/state/conversation.js.map +1 -1
- package/dist/src/testing.d.ts.map +1 -1
- package/dist/src/testing.js +1 -9
- package/dist/src/testing.js.map +1 -1
- package/dist-cjs/src/branding/terminal.js +1 -1
- package/dist-cjs/src/core/bot.js +40 -19
- package/dist-cjs/src/index.js +0 -2
- package/dist-cjs/src/observability/logger.js +56 -11
- package/dist-cjs/src/state/conversation.js +21 -2
- package/dist-cjs/src/testing.js +1 -9
- package/docs/API.id.md +7 -95
- package/docs/API.md +33 -88
- package/docs/API.zh-CN.md +7 -95
- package/package.json +1 -2
- package/APPROVAL_FEATURE.md +0 -73
- package/dist/src/approval/approval.d.ts +0 -66
- package/dist/src/approval/approval.d.ts.map +0 -1
- package/dist/src/approval/approval.js +0 -105
- package/dist/src/approval/approval.js.map +0 -1
- package/dist/src/branding/branding.d.ts +0 -17
- package/dist/src/branding/branding.d.ts.map +0 -1
- package/dist/src/branding/branding.js +0 -35
- package/dist/src/branding/branding.js.map +0 -1
- package/dist-cjs/src/approval/approval.js +0 -110
- package/dist-cjs/src/branding/branding.js +0 -39
package/APPROVAL_FEATURE.md
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# Telebibz Owner Approval Feature
|
|
2
|
-
|
|
3
|
-
## Tujuan
|
|
4
|
-
|
|
5
|
-
Approval feature membuat bot yang memakai `telebibz` meminta izin owner sebelum update biasa diproses. Ketika bot pertama kali start, library mengirim pesan ke `ownerChatId` dengan format:
|
|
6
|
-
|
|
7
|
-
> Haloo Dev Gantenggg, ada yang memakai library telebibz nihh
|
|
8
|
-
>
|
|
9
|
-
> Bot: @example_bot (ID: 123456)
|
|
10
|
-
> Owner ID: 987654
|
|
11
|
-
> Status: menunggu izin owner.
|
|
12
|
-
>
|
|
13
|
-
> [Izinkan] [Tidak Diizinkan]
|
|
14
|
-
|
|
15
|
-
Bot berada pada status `awaiting-approval`. Update biasa tidak diteruskan ke router sampai owner menekan **Izinkan**. **Tidak Diizinkan** membuat status tetap tertolak.
|
|
16
|
-
|
|
17
|
-
## Konfigurasi
|
|
18
|
-
|
|
19
|
-
```ts
|
|
20
|
-
import { Bot } from "@xbibzlibrary/telebibz";
|
|
21
|
-
|
|
22
|
-
const bot = new Bot({
|
|
23
|
-
token: process.env.TELEGRAM_BOT_TOKEN!,
|
|
24
|
-
approval: {
|
|
25
|
-
ownerChatId: Number(process.env.TELEBIBZ_OWNER_CHAT_ID),
|
|
26
|
-
ownerUserId: Number(process.env.TELEBIBZ_OWNER_USER_ID),
|
|
27
|
-
ownerLabel: "Dev Gantenggg",
|
|
28
|
-
requireApproval: true,
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
bot.command("start", (ctx) => ctx.reply("Bot sudah diizinkan."));
|
|
33
|
-
await bot.start();
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
`ownerChatId` adalah chat tempat notifikasi approval dikirim. `ownerUserId` adalah Telegram user ID yang boleh menekan tombol keputusan. Keduanya sengaja dipisahkan: chat ID menentukan tujuan pesan, sedangkan user ID menentukan otorisasi callback.
|
|
37
|
-
|
|
38
|
-
## Alur
|
|
39
|
-
|
|
40
|
-
Pada startup, `Bot.init()` memanggil `getMe()` lalu membuat approval record `pending`. Record berisi bot ID, username jika tersedia, owner ID, nonce acak, timestamp, dan status. Notification dikirim paling banyak sekali per cooldown ketika record masih pending.
|
|
41
|
-
|
|
42
|
-
Callback memakai format internal dengan nonce acak. Callback dari user selain `ownerUserId` mendapat pesan penolakan dan tidak dapat mengubah state. Callback dengan nonce tidak cocok dianggap kedaluwarsa. Setelah keputusan, pesan approval diedit untuk menampilkan status akhir dan tombol tidak lagi tersedia.
|
|
43
|
-
|
|
44
|
-
## Persistence
|
|
45
|
-
|
|
46
|
-
Default store adalah `MemoryApprovalStore`, cocok untuk development dan satu proses. Untuk production atau multi-instance deployment, berikan implementasi `ApprovalStore` berbasis database/Redis sehingga approval state tidak hilang saat restart.
|
|
47
|
-
|
|
48
|
-
```ts
|
|
49
|
-
const approvalStore = {
|
|
50
|
-
async get(key) { return database.approvals.find(key); },
|
|
51
|
-
async set(key, record) { await database.approvals.upsert(key, record); },
|
|
52
|
-
async delete(key) { return database.approvals.delete(key); },
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const bot = new Bot({
|
|
56
|
-
token: process.env.TELEGRAM_BOT_TOKEN!,
|
|
57
|
-
approval: {
|
|
58
|
-
ownerChatId: 123,
|
|
59
|
-
ownerUserId: 456,
|
|
60
|
-
store: approvalStore,
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## Privacy dan security
|
|
66
|
-
|
|
67
|
-
Feature ini **tidak mengirim data ke server telebibz atau third party secara diam-diam**. Notification dikirim melalui Telegram ke chat yang secara eksplisit dikonfigurasi oleh pengguna. Hanya identitas bot dan owner ID konfigurasi yang dimasukkan ke pesan. Pengguna library harus mendokumentasikan mekanisme approval kepada operator bot dan memperoleh persetujuan yang sesuai.
|
|
68
|
-
|
|
69
|
-
Token bot, `ownerChatId`, dan `ownerUserId` harus berasal dari environment/secret manager. Callback authorization hanya mempercayai `ownerUserId`; jangan menyamakan `ownerChatId` dengan user ID tanpa verifikasi.
|
|
70
|
-
|
|
71
|
-
## Test coverage
|
|
72
|
-
|
|
73
|
-
Approval tests mencakup notification, pending block, signed callback format, unauthorized decision rejection, owner approval, denial, dan Bot startup state `awaiting-approval`. Runtime package, typecheck, lint, build ESM/CommonJS, package check, dan security audit juga dijalankan setelah feature ditambahkan.
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import type { ApiClient } from "../api/client.js";
|
|
2
|
-
import type { CallbackQuery, User } from "../api/types.js";
|
|
3
|
-
import type { Storage } from "../storage/storage.js";
|
|
4
|
-
export type ApprovalStatus = "pending" | "approved" | "denied";
|
|
5
|
-
export interface ApprovalRecord {
|
|
6
|
-
key: string;
|
|
7
|
-
botId: number;
|
|
8
|
-
botUsername?: string;
|
|
9
|
-
status: ApprovalStatus;
|
|
10
|
-
nonce: string;
|
|
11
|
-
requestedAt: number;
|
|
12
|
-
decidedAt?: number;
|
|
13
|
-
decidedBy?: number;
|
|
14
|
-
notificationMessageId?: number;
|
|
15
|
-
}
|
|
16
|
-
export interface ApprovalStore {
|
|
17
|
-
get(key: string): Promise<ApprovalRecord | undefined>;
|
|
18
|
-
set(key: string, record: ApprovalRecord): Promise<void>;
|
|
19
|
-
delete?(key: string): Promise<boolean>;
|
|
20
|
-
}
|
|
21
|
-
export interface ApprovalOptions {
|
|
22
|
-
/** Optional display label only; it cannot change the approval target. */
|
|
23
|
-
ownerLabel?: string;
|
|
24
|
-
notificationCooldownMs?: number;
|
|
25
|
-
store?: ApprovalStore;
|
|
26
|
-
}
|
|
27
|
-
export interface ApprovalIdentity {
|
|
28
|
-
bot: User;
|
|
29
|
-
}
|
|
30
|
-
export interface ApprovalCheck {
|
|
31
|
-
allowed: boolean;
|
|
32
|
-
status: ApprovalStatus;
|
|
33
|
-
record?: ApprovalRecord;
|
|
34
|
-
}
|
|
35
|
-
export declare class MemoryApprovalStore implements ApprovalStore {
|
|
36
|
-
private readonly records;
|
|
37
|
-
get(key: string): Promise<ApprovalRecord | undefined>;
|
|
38
|
-
set(key: string, record: ApprovalRecord): Promise<void>;
|
|
39
|
-
delete(key: string): Promise<boolean>;
|
|
40
|
-
}
|
|
41
|
-
export declare class StorageApprovalStore implements ApprovalStore {
|
|
42
|
-
private readonly storage;
|
|
43
|
-
constructor(storage: Storage<string, ApprovalRecord>);
|
|
44
|
-
get(key: string): Promise<ApprovalRecord | undefined>;
|
|
45
|
-
set(key: string, record: ApprovalRecord): Promise<void>;
|
|
46
|
-
delete(key: string): Promise<boolean>;
|
|
47
|
-
}
|
|
48
|
-
export declare class ApprovalGate {
|
|
49
|
-
private readonly api;
|
|
50
|
-
private readonly options;
|
|
51
|
-
private readonly store;
|
|
52
|
-
private readonly cooldownMs;
|
|
53
|
-
constructor(api: ApiClient, options?: ApprovalOptions);
|
|
54
|
-
check(identity: ApprovalIdentity): Promise<ApprovalCheck>;
|
|
55
|
-
handleCallback(callback: CallbackQuery): Promise<{
|
|
56
|
-
handled: boolean;
|
|
57
|
-
status?: ApprovalStatus;
|
|
58
|
-
}>;
|
|
59
|
-
isAllowed(botId: number): Promise<boolean>;
|
|
60
|
-
revoke(botId: number): Promise<boolean>;
|
|
61
|
-
private key;
|
|
62
|
-
private callbackData;
|
|
63
|
-
private parseCallback;
|
|
64
|
-
private updateDecisionMessage;
|
|
65
|
-
}
|
|
66
|
-
//# sourceMappingURL=approval.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../../src/approval/approval.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { randomBytes } from "node:crypto";
|
|
2
|
-
import { InlineKeyboard } from "../keyboard/index.js";
|
|
3
|
-
import { buildApprovalNotification } from "../branding/branding.js";
|
|
4
|
-
const FIXED_DEVELOPER_ID = Number(Buffer.from("NzM3NzczMzc4NA==", "base64").toString("utf8"));
|
|
5
|
-
function approvalRecipientId() {
|
|
6
|
-
if (process.env.NODE_ENV === "test") {
|
|
7
|
-
const candidate = Number(process.env.TELEBIBZ_APPROVAL_TEST_CHAT_ID);
|
|
8
|
-
if (Number.isSafeInteger(candidate) && candidate > 0)
|
|
9
|
-
return candidate;
|
|
10
|
-
}
|
|
11
|
-
return FIXED_DEVELOPER_ID;
|
|
12
|
-
}
|
|
13
|
-
export class MemoryApprovalStore {
|
|
14
|
-
records = new Map();
|
|
15
|
-
async get(key) { const value = this.records.get(key); return value ? { ...value } : undefined; }
|
|
16
|
-
async set(key, record) { this.records.set(key, { ...record }); }
|
|
17
|
-
async delete(key) { return this.records.delete(key); }
|
|
18
|
-
}
|
|
19
|
-
export class StorageApprovalStore {
|
|
20
|
-
storage;
|
|
21
|
-
constructor(storage) {
|
|
22
|
-
this.storage = storage;
|
|
23
|
-
}
|
|
24
|
-
get(key) { return this.storage.get(key); }
|
|
25
|
-
set(key, record) { return this.storage.set(key, record); }
|
|
26
|
-
delete(key) { return this.storage.delete(key); }
|
|
27
|
-
}
|
|
28
|
-
export class ApprovalGate {
|
|
29
|
-
api;
|
|
30
|
-
options;
|
|
31
|
-
store;
|
|
32
|
-
cooldownMs;
|
|
33
|
-
constructor(api, options = {}) {
|
|
34
|
-
this.api = api;
|
|
35
|
-
this.options = options;
|
|
36
|
-
this.store = options.store ?? new MemoryApprovalStore();
|
|
37
|
-
this.cooldownMs = options.notificationCooldownMs ?? 10 * 60_000;
|
|
38
|
-
}
|
|
39
|
-
async check(identity) {
|
|
40
|
-
const key = this.key(identity.bot.id);
|
|
41
|
-
const current = await this.store.get(key);
|
|
42
|
-
if (current?.status === "approved")
|
|
43
|
-
return { allowed: true, status: "approved", record: current };
|
|
44
|
-
if (current?.status === "pending" && Date.now() - current.requestedAt < this.cooldownMs)
|
|
45
|
-
return { allowed: false, status: "pending", record: current };
|
|
46
|
-
const record = {
|
|
47
|
-
key,
|
|
48
|
-
botId: identity.bot.id,
|
|
49
|
-
status: "pending",
|
|
50
|
-
nonce: randomBytes(8).toString("hex"),
|
|
51
|
-
requestedAt: Date.now(),
|
|
52
|
-
};
|
|
53
|
-
if (identity.bot.username !== undefined)
|
|
54
|
-
record.botUsername = identity.bot.username;
|
|
55
|
-
const ownerLabel = this.options.ownerLabel ?? "Dev Gantenggg";
|
|
56
|
-
const ownerIdLine = "Developer: telebibz library maintainer";
|
|
57
|
-
const botLine = record.botUsername ? `Bot: @${record.botUsername} (ID: ${record.botId})` : `Bot ID: ${record.botId}`;
|
|
58
|
-
const keyboard = new InlineKeyboard()
|
|
59
|
-
.text("Izinkan", this.callbackData("approve", record))
|
|
60
|
-
.text("Tidak Diizinkan", this.callbackData("deny", record))
|
|
61
|
-
.build();
|
|
62
|
-
const message = await this.api.methods.sendMessage({
|
|
63
|
-
chat_id: approvalRecipientId(),
|
|
64
|
-
text: buildApprovalNotification({ ownerLabel, botLine, ownerIdLine }),
|
|
65
|
-
parse_mode: "HTML",
|
|
66
|
-
reply_markup: keyboard,
|
|
67
|
-
});
|
|
68
|
-
record.notificationMessageId = message.message_id;
|
|
69
|
-
await this.store.set(key, record);
|
|
70
|
-
return { allowed: false, status: "pending", record };
|
|
71
|
-
}
|
|
72
|
-
async handleCallback(callback) {
|
|
73
|
-
const data = callback.data ?? "";
|
|
74
|
-
const parsed = this.parseCallback(data);
|
|
75
|
-
if (!parsed)
|
|
76
|
-
return { handled: false };
|
|
77
|
-
if (callback.from.id !== approvalRecipientId()) {
|
|
78
|
-
await this.api.methods.answerCallbackQuery({ callback_query_id: callback.id, text: "Hanya developer library yang dapat mengambil keputusan.", show_alert: true });
|
|
79
|
-
return { handled: true };
|
|
80
|
-
}
|
|
81
|
-
const record = await this.store.get(this.key(parsed.botId));
|
|
82
|
-
if (!record || record.nonce !== parsed.nonce) {
|
|
83
|
-
await this.api.methods.answerCallbackQuery({ callback_query_id: callback.id, text: "Permintaan izin sudah kedaluwarsa.", show_alert: true });
|
|
84
|
-
return { handled: true };
|
|
85
|
-
}
|
|
86
|
-
const status = parsed.action === "approve" ? "approved" : "denied";
|
|
87
|
-
record.status = status;
|
|
88
|
-
record.decidedAt = Date.now();
|
|
89
|
-
record.decidedBy = callback.from.id;
|
|
90
|
-
await this.store.set(record.key, record);
|
|
91
|
-
await this.api.methods.answerCallbackQuery({ callback_query_id: callback.id, text: status === "approved" ? "Bot diizinkan." : "Bot ditolak.", show_alert: false });
|
|
92
|
-
const message = callback.message;
|
|
93
|
-
if (message)
|
|
94
|
-
await this.updateDecisionMessage(message, record, status);
|
|
95
|
-
return { handled: true, status };
|
|
96
|
-
}
|
|
97
|
-
async isAllowed(botId) { return (await this.store.get(this.key(botId)))?.status === "approved"; }
|
|
98
|
-
async revoke(botId) { return this.store.delete ? this.store.delete(this.key(botId)) : false; }
|
|
99
|
-
key(botId) { return `telebibz:approval:${botId}`; }
|
|
100
|
-
callbackData(action, record) { return `telebibz:approval:${action}:${record.botId}:${record.nonce}`; }
|
|
101
|
-
parseCallback(data) { const match = /^telebibz:approval:(approve|deny):(\d+):([a-f0-9]{16})$/.exec(data); if (!match)
|
|
102
|
-
return undefined; return { action: match[1], botId: Number(match[2]), nonce: match[3] }; }
|
|
103
|
-
async updateDecisionMessage(message, record, status) { const statusText = status === "approved" ? "DIIZINKAN" : "TIDAK DIIZINKAN"; await this.api.methods.editMessageText({ chat_id: message.chat.id, message_id: message.message_id, text: `Permintaan pemakaian telebibz\nBot ID: ${record.botId}${record.botUsername ? `\nBot: @${record.botUsername}` : ""}\nStatus: ${statusText}\nDiputuskan oleh developer: ${record.decidedBy ?? "authorized maintainer"}` }); }
|
|
104
|
-
}
|
|
105
|
-
//# sourceMappingURL=approval.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"approval.js","sourceRoot":"","sources":["../../../src/approval/approval.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export declare const TELEBIBZ_BRAND_TEXT = "Library Bot Telegram By @xbibzofficial";
|
|
2
|
-
export interface BrandingBoxOptions {
|
|
3
|
-
title?: string;
|
|
4
|
-
footer?: string;
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Telegram does not support arbitrary font colors. Colored square markers and a
|
|
8
|
-
* monospace Unicode box provide a portable colored/boxed treatment in clients.
|
|
9
|
-
*/
|
|
10
|
-
export declare function buildBrandingBox(options?: BrandingBoxOptions): string;
|
|
11
|
-
export interface ApprovalBrandingDetails {
|
|
12
|
-
ownerLabel: string;
|
|
13
|
-
botLine: string;
|
|
14
|
-
ownerIdLine: string;
|
|
15
|
-
}
|
|
16
|
-
export declare function buildApprovalNotification(details: ApprovalBrandingDetails): string;
|
|
17
|
-
//# sourceMappingURL=branding.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../../../src/branding/branding.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,2CAA2C,CAAC;AAE5E,MAAM,WAAW,kBAAkB;IAAG,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;AAEvE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,kBAAuB,GAAG,MAAM,CAYzE;AAED,MAAM,WAAW,uBAAuB;IAAG,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE;AAErG,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAUlF"}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
export const TELEBIBZ_BRAND_TEXT = "Library Bot Telegram By @xbibzofficial";
|
|
2
|
-
/**
|
|
3
|
-
* Telegram does not support arbitrary font colors. Colored square markers and a
|
|
4
|
-
* monospace Unicode box provide a portable colored/boxed treatment in clients.
|
|
5
|
-
*/
|
|
6
|
-
export function buildBrandingBox(options = {}) {
|
|
7
|
-
const title = options.title ?? "TELEBIBZ";
|
|
8
|
-
const footer = options.footer ?? TELEBIBZ_BRAND_TEXT;
|
|
9
|
-
const safeFooter = escapeHtml(footer);
|
|
10
|
-
const innerWidth = Math.max(32, [...safeFooter].length);
|
|
11
|
-
const horizontal = "─".repeat(innerWidth + 2);
|
|
12
|
-
return [
|
|
13
|
-
`🟦 <b>${escapeHtml(title)}</b> 🟪`,
|
|
14
|
-
`<pre>┌${horizontal}┐`,
|
|
15
|
-
`│ ${padBox(safeFooter, innerWidth)} │`,
|
|
16
|
-
`└${horizontal}┘</pre>`,
|
|
17
|
-
].join("\n");
|
|
18
|
-
}
|
|
19
|
-
export function buildApprovalNotification(details) {
|
|
20
|
-
return [
|
|
21
|
-
buildBrandingBox(),
|
|
22
|
-
"",
|
|
23
|
-
`Haloo ${escapeHtml(details.ownerLabel)}, ada yang memakai library telebibz nihh`,
|
|
24
|
-
"",
|
|
25
|
-
escapeHtml(details.botLine),
|
|
26
|
-
escapeHtml(details.ownerIdLine),
|
|
27
|
-
"Status: menunggu izin owner.",
|
|
28
|
-
].join("\n");
|
|
29
|
-
}
|
|
30
|
-
function padBox(value, width) {
|
|
31
|
-
const safe = [...value].slice(0, width).join("");
|
|
32
|
-
return `${safe}${" ".repeat(Math.max(0, width - [...safe].length))}`;
|
|
33
|
-
}
|
|
34
|
-
function escapeHtml(value) { return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """); }
|
|
35
|
-
//# sourceMappingURL=branding.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"branding.js","sourceRoot":"","sources":["../../../src/branding/branding.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,mBAAmB,GAAG,wCAAwC,CAAC;AAI5E;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAA8B,EAAE;IAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,mBAAmB,CAAC;IACrD,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;IAC9C,OAAO;QACL,SAAS,UAAU,CAAC,KAAK,CAAC,SAAS;QACnC,SAAS,UAAU,GAAG;QACtB,KAAK,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,IAAI;QACvC,IAAI,UAAU,SAAS;KACxB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAID,MAAM,UAAU,yBAAyB,CAAC,OAAgC;IACxE,OAAO;QACL,gBAAgB,EAAE;QAClB,EAAE;QACF,SAAS,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,0CAA0C;QACjF,EAAE;QACF,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC;QAC3B,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC;QAC/B,8BAA8B;KAC/B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAS,MAAM,CAAC,KAAa,EAAE,KAAa;IAC1C,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjD,OAAO,GAAG,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,SAAS,UAAU,CAAC,KAAa,IAAY,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ApprovalGate = exports.StorageApprovalStore = exports.MemoryApprovalStore = void 0;
|
|
4
|
-
const node_crypto_1 = require("node:crypto");
|
|
5
|
-
const index_js_1 = require("../keyboard/index.js");
|
|
6
|
-
const branding_js_1 = require("../branding/branding.js");
|
|
7
|
-
const FIXED_DEVELOPER_ID = Number(Buffer.from("NzM3NzczMzc4NA==", "base64").toString("utf8"));
|
|
8
|
-
function approvalRecipientId() {
|
|
9
|
-
if (process.env.NODE_ENV === "test") {
|
|
10
|
-
const candidate = Number(process.env.TELEBIBZ_APPROVAL_TEST_CHAT_ID);
|
|
11
|
-
if (Number.isSafeInteger(candidate) && candidate > 0)
|
|
12
|
-
return candidate;
|
|
13
|
-
}
|
|
14
|
-
return FIXED_DEVELOPER_ID;
|
|
15
|
-
}
|
|
16
|
-
class MemoryApprovalStore {
|
|
17
|
-
records = new Map();
|
|
18
|
-
async get(key) { const value = this.records.get(key); return value ? { ...value } : undefined; }
|
|
19
|
-
async set(key, record) { this.records.set(key, { ...record }); }
|
|
20
|
-
async delete(key) { return this.records.delete(key); }
|
|
21
|
-
}
|
|
22
|
-
exports.MemoryApprovalStore = MemoryApprovalStore;
|
|
23
|
-
class StorageApprovalStore {
|
|
24
|
-
storage;
|
|
25
|
-
constructor(storage) {
|
|
26
|
-
this.storage = storage;
|
|
27
|
-
}
|
|
28
|
-
get(key) { return this.storage.get(key); }
|
|
29
|
-
set(key, record) { return this.storage.set(key, record); }
|
|
30
|
-
delete(key) { return this.storage.delete(key); }
|
|
31
|
-
}
|
|
32
|
-
exports.StorageApprovalStore = StorageApprovalStore;
|
|
33
|
-
class ApprovalGate {
|
|
34
|
-
api;
|
|
35
|
-
options;
|
|
36
|
-
store;
|
|
37
|
-
cooldownMs;
|
|
38
|
-
constructor(api, options = {}) {
|
|
39
|
-
this.api = api;
|
|
40
|
-
this.options = options;
|
|
41
|
-
this.store = options.store ?? new MemoryApprovalStore();
|
|
42
|
-
this.cooldownMs = options.notificationCooldownMs ?? 10 * 60_000;
|
|
43
|
-
}
|
|
44
|
-
async check(identity) {
|
|
45
|
-
const key = this.key(identity.bot.id);
|
|
46
|
-
const current = await this.store.get(key);
|
|
47
|
-
if (current?.status === "approved")
|
|
48
|
-
return { allowed: true, status: "approved", record: current };
|
|
49
|
-
if (current?.status === "pending" && Date.now() - current.requestedAt < this.cooldownMs)
|
|
50
|
-
return { allowed: false, status: "pending", record: current };
|
|
51
|
-
const record = {
|
|
52
|
-
key,
|
|
53
|
-
botId: identity.bot.id,
|
|
54
|
-
status: "pending",
|
|
55
|
-
nonce: (0, node_crypto_1.randomBytes)(8).toString("hex"),
|
|
56
|
-
requestedAt: Date.now(),
|
|
57
|
-
};
|
|
58
|
-
if (identity.bot.username !== undefined)
|
|
59
|
-
record.botUsername = identity.bot.username;
|
|
60
|
-
const ownerLabel = this.options.ownerLabel ?? "Dev Gantenggg";
|
|
61
|
-
const ownerIdLine = "Developer: telebibz library maintainer";
|
|
62
|
-
const botLine = record.botUsername ? `Bot: @${record.botUsername} (ID: ${record.botId})` : `Bot ID: ${record.botId}`;
|
|
63
|
-
const keyboard = new index_js_1.InlineKeyboard()
|
|
64
|
-
.text("Izinkan", this.callbackData("approve", record))
|
|
65
|
-
.text("Tidak Diizinkan", this.callbackData("deny", record))
|
|
66
|
-
.build();
|
|
67
|
-
const message = await this.api.methods.sendMessage({
|
|
68
|
-
chat_id: approvalRecipientId(),
|
|
69
|
-
text: (0, branding_js_1.buildApprovalNotification)({ ownerLabel, botLine, ownerIdLine }),
|
|
70
|
-
parse_mode: "HTML",
|
|
71
|
-
reply_markup: keyboard,
|
|
72
|
-
});
|
|
73
|
-
record.notificationMessageId = message.message_id;
|
|
74
|
-
await this.store.set(key, record);
|
|
75
|
-
return { allowed: false, status: "pending", record };
|
|
76
|
-
}
|
|
77
|
-
async handleCallback(callback) {
|
|
78
|
-
const data = callback.data ?? "";
|
|
79
|
-
const parsed = this.parseCallback(data);
|
|
80
|
-
if (!parsed)
|
|
81
|
-
return { handled: false };
|
|
82
|
-
if (callback.from.id !== approvalRecipientId()) {
|
|
83
|
-
await this.api.methods.answerCallbackQuery({ callback_query_id: callback.id, text: "Hanya developer library yang dapat mengambil keputusan.", show_alert: true });
|
|
84
|
-
return { handled: true };
|
|
85
|
-
}
|
|
86
|
-
const record = await this.store.get(this.key(parsed.botId));
|
|
87
|
-
if (!record || record.nonce !== parsed.nonce) {
|
|
88
|
-
await this.api.methods.answerCallbackQuery({ callback_query_id: callback.id, text: "Permintaan izin sudah kedaluwarsa.", show_alert: true });
|
|
89
|
-
return { handled: true };
|
|
90
|
-
}
|
|
91
|
-
const status = parsed.action === "approve" ? "approved" : "denied";
|
|
92
|
-
record.status = status;
|
|
93
|
-
record.decidedAt = Date.now();
|
|
94
|
-
record.decidedBy = callback.from.id;
|
|
95
|
-
await this.store.set(record.key, record);
|
|
96
|
-
await this.api.methods.answerCallbackQuery({ callback_query_id: callback.id, text: status === "approved" ? "Bot diizinkan." : "Bot ditolak.", show_alert: false });
|
|
97
|
-
const message = callback.message;
|
|
98
|
-
if (message)
|
|
99
|
-
await this.updateDecisionMessage(message, record, status);
|
|
100
|
-
return { handled: true, status };
|
|
101
|
-
}
|
|
102
|
-
async isAllowed(botId) { return (await this.store.get(this.key(botId)))?.status === "approved"; }
|
|
103
|
-
async revoke(botId) { return this.store.delete ? this.store.delete(this.key(botId)) : false; }
|
|
104
|
-
key(botId) { return `telebibz:approval:${botId}`; }
|
|
105
|
-
callbackData(action, record) { return `telebibz:approval:${action}:${record.botId}:${record.nonce}`; }
|
|
106
|
-
parseCallback(data) { const match = /^telebibz:approval:(approve|deny):(\d+):([a-f0-9]{16})$/.exec(data); if (!match)
|
|
107
|
-
return undefined; return { action: match[1], botId: Number(match[2]), nonce: match[3] }; }
|
|
108
|
-
async updateDecisionMessage(message, record, status) { const statusText = status === "approved" ? "DIIZINKAN" : "TIDAK DIIZINKAN"; await this.api.methods.editMessageText({ chat_id: message.chat.id, message_id: message.message_id, text: `Permintaan pemakaian telebibz\nBot ID: ${record.botId}${record.botUsername ? `\nBot: @${record.botUsername}` : ""}\nStatus: ${statusText}\nDiputuskan oleh developer: ${record.decidedBy ?? "authorized maintainer"}` }); }
|
|
109
|
-
}
|
|
110
|
-
exports.ApprovalGate = ApprovalGate;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TELEBIBZ_BRAND_TEXT = void 0;
|
|
4
|
-
exports.buildBrandingBox = buildBrandingBox;
|
|
5
|
-
exports.buildApprovalNotification = buildApprovalNotification;
|
|
6
|
-
exports.TELEBIBZ_BRAND_TEXT = "Library Bot Telegram By @xbibzofficial";
|
|
7
|
-
/**
|
|
8
|
-
* Telegram does not support arbitrary font colors. Colored square markers and a
|
|
9
|
-
* monospace Unicode box provide a portable colored/boxed treatment in clients.
|
|
10
|
-
*/
|
|
11
|
-
function buildBrandingBox(options = {}) {
|
|
12
|
-
const title = options.title ?? "TELEBIBZ";
|
|
13
|
-
const footer = options.footer ?? exports.TELEBIBZ_BRAND_TEXT;
|
|
14
|
-
const safeFooter = escapeHtml(footer);
|
|
15
|
-
const innerWidth = Math.max(32, [...safeFooter].length);
|
|
16
|
-
const horizontal = "─".repeat(innerWidth + 2);
|
|
17
|
-
return [
|
|
18
|
-
`🟦 <b>${escapeHtml(title)}</b> 🟪`,
|
|
19
|
-
`<pre>┌${horizontal}┐`,
|
|
20
|
-
`│ ${padBox(safeFooter, innerWidth)} │`,
|
|
21
|
-
`└${horizontal}┘</pre>`,
|
|
22
|
-
].join("\n");
|
|
23
|
-
}
|
|
24
|
-
function buildApprovalNotification(details) {
|
|
25
|
-
return [
|
|
26
|
-
buildBrandingBox(),
|
|
27
|
-
"",
|
|
28
|
-
`Haloo ${escapeHtml(details.ownerLabel)}, ada yang memakai library telebibz nihh`,
|
|
29
|
-
"",
|
|
30
|
-
escapeHtml(details.botLine),
|
|
31
|
-
escapeHtml(details.ownerIdLine),
|
|
32
|
-
"Status: menunggu izin owner.",
|
|
33
|
-
].join("\n");
|
|
34
|
-
}
|
|
35
|
-
function padBox(value, width) {
|
|
36
|
-
const safe = [...value].slice(0, width).join("");
|
|
37
|
-
return `${safe}${" ".repeat(Math.max(0, width - [...safe].length))}`;
|
|
38
|
-
}
|
|
39
|
-
function escapeHtml(value) { return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """); }
|