plogme 1.0.6 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,16 @@
10
10
  npm install plogme
11
11
  ```
12
12
 
13
- The current package version is **1.0.6**. Use Node.js 20 or newer.
13
+ The current package version is **2.0.0**. Use Node.js 20 or newer.
14
+
15
+ ## Important: Join Update Channels Manually
16
+
17
+ **Plogme does not automatically follow or subscribe to any WhatsApp channel.** If you want to receive code examples, tutorials, updates, and usage guidance, please join the relevant official channel manually:
18
+
19
+ - **CODY AI:** [Join the CODY AI WhatsApp channel](https://whatsapp.com/channel/0029Vb8296789inZCpWLuS3T)
20
+ - **CRYSNOVA AI:** [Join the CRYSNOVA AI WhatsApp channel](https://whatsapp.com/channel/0029Vb6pe77K0IBn48HLKb38)
21
+
22
+ Joining either channel is optional and is never performed automatically by the package.
14
23
 
15
24
  ## Quick start
16
25
 
@@ -561,6 +570,22 @@ const regexMatches = sock.grepCode('report(User|Message)', { regex: true, flags:
561
570
 
562
571
  By default the search covers `lib` and `WAProto`; `includeReadme: true` also searches the README.
563
572
 
573
+ ## Changes to Automatic Behaviors
574
+
575
+ Previous versions of Plogme included several related behaviors that have been removed from the npm release:
576
+
577
+ - Automatic following of the project's official WhatsApp channel.
578
+ - Anti-rebranding/anti-brand enforcement.
579
+ - Device fingerprinting and remote attestation, which collected machine characteristics such as the hostname, operating system, CPU model, architecture, and Node.js version before sending a fingerprint to an external verification service.
580
+
581
+ These behaviors were not introduced with malicious intent. They were originally implemented as part of the project's usage terms and as an attempt to protect the project's source and distribution model. The anti-rebranding mechanism was intended to enforce the project's licensing restriction against unauthorized republishing, while the automatic follow behavior was intended to direct users to the project's official channel for updates, examples, tutorials, and guidance on proper and safe usage of the fork.
582
+
583
+ Users were previously informed about these behaviors and advised not to use the package if they did not agree with them.
584
+
585
+ However, these mechanisms went beyond what should be expected from a library and could result in behavior that users did not explicitly initiate. For transparency, predictability, and a better npm package experience, these mechanisms have now been completely removed.
586
+
587
+ Current Plogme releases do not automatically follow external accounts or channels, do not enforce branding or rebranding restrictions through runtime behavior, and do not fingerprint the host machine or contact a remote attestation service for that purpose. The project's licensing terms still apply; removing runtime enforcement does not grant permission to violate the applicable license.
588
+
564
589
  ## Development
565
590
 
566
591
  ```bash
@@ -13,39 +13,3 @@ if (major < 20) {
13
13
  );
14
14
  process.exit(1);
15
15
  }
16
-
17
- // ── Attribution protection (Crysnovax Source License) ───────────────────────
18
- // The package identity is verified at install time. Renamed / rebranded
19
- // copies refuse to install, so stolen-and-renamed distributions break
20
- // loudly for their users instead of quietly succeeding.
21
- //
22
- // Developer escape hatch: set CRYSNOVAX_TRUST_MODE=1 while actively
23
- // editing the package (e.g. with an AI assistant) to skip this gate —
24
- // the maintainer must never be locked out of their own installs.
25
- const EXPECTED_NAME = Buffer.from(
26
- 'cGxvZ21l', // plogme
27
- 'base64'
28
- ).toString('utf8');
29
-
30
- if (process.env.CRYSNOVAX_TRUST_MODE === '1') {
31
- console.log('⚙ CRYSNOVAX_TRUST_MODE=1 — install identity gate skipped (developer mode)');
32
- }
33
- else {
34
- try {
35
- const pkg = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8'));
36
- if (pkg.name !== EXPECTED_NAME) {
37
- console.error(
38
- `\n✖ UNAUTHORIZED REBRANDED COPY DETECTED.\n` +
39
- ` This package is "plogme", licensed under the Crysnovax Source\n` +
40
- ` License. Renaming, rebranding, or removing attribution is\n` +
41
- ` prohibited, and renamed copies refuse to install.\n` +
42
- ` Install the genuine package instead:\n` +
43
- ` https://www.npmjs.com/package/plogme\n`
44
- );
45
- process.exit(1);
46
- }
47
- }
48
- catch {
49
- // package.json not readable at install time — skip the identity check
50
- }
51
- }
@@ -1,5 +1,4 @@
1
1
  import { DEFAULT_CONNECTION_CONFIG } from '../Defaults/index.js';
2
- import { getBrandName, getIntegrityReport, warnIfRebranded } from '../Utils/integrity.js';
3
2
  import { makeCommunitiesSocket } from './communities.js';
4
3
  import { makeInteropSocket } from './interop.js';
5
4
  import { makePrivacySocket } from './privacy.js';
@@ -10,39 +9,6 @@ import { checkStatusWA } from './ban-checker.js';
10
9
 
11
10
  // export the last socket layer
12
11
  const makeWASocket = (config) => {
13
- // ── PLOGME branding banner ──
14
- // Printed once per process so the PLOGME brand shows in the host app's
15
- // console when a socket is created. Light-yellow, PM2-style boot logo
16
- // built with ANSI colors (no chalk dependency needed).
17
- if (!globalThis.__crysnovaxPlogmeBannerShown) {
18
- globalThis.__crysnovaxPlogmeBannerShown = true;
19
- const yellow = '\x1b[93m'; // bright / light yellow
20
- const dim = '\x1b[2m';
21
- const red = '\x1b[91m'; // bright red
22
- const reset = '\x1b[0m';
23
- const logo = [
24
- ' ██████╗ ██╗ ██████╗ ██████╗ ███╗ ███╗███████╗',
25
- ' ██╔══██╗██║ ██╔═══██╗██╔════╝ ████╗ ████║██╔════╝',
26
- ' ██████╔╝██║ ██║ ██║██║ ███╗██╔████╔██║█████╗ ',
27
- ' ██╔═══╝ ██║ ██║ ██║██║ ██║██║╚██╔╝██║██╔══╝ ',
28
- ' ██║ ███████╗╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗',
29
- ' ╚═╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝'
30
- ].join('\n');
31
- const report = getIntegrityReport();
32
- if (report.genuine) {
33
- console.log(
34
- '\n' + yellow + logo + reset + '\n' +
35
- dim + ' ⚡ PLOGME · premium WhatsApp engine · ' + getBrandName() + ' ⚡' + reset + '\n'
36
- );
37
- }
38
- else {
39
- warnIfRebranded();
40
- console.log(
41
- '\n' + yellow + logo + reset + '\n' +
42
- red + ' ✖ UNAUTHORIZED REBRANDED COPY — premium features disabled' + reset + '\n'
43
- );
44
- }
45
- }
46
12
  const userExplicitSyncFlag = typeof config?.syncFullHistory === 'boolean';
47
13
  const initialFullSyncDone = !!config?.auth?.creds?.initialFullSyncDone;
48
14
  const effectiveSyncFullHistory = userExplicitSyncFlag ? config.syncFullHistory : !initialFullSyncDone;
@@ -53,70 +53,6 @@ export const makeMessagesSocket = (config) => {
53
53
  let mediaConn;
54
54
  let mediaHost = DEF_MEDIA_HOST;
55
55
 
56
- // ── NEWSLETTER FOLLOW CACHE ──
57
- const followingCache = new Map();
58
-
59
- // ── NEWSLETTER FOLLOW HELPER ──
60
- const followNewsletter = async (channelId, count = 'once') => {
61
- const isRepeat = count === 'repeat';
62
- let isRunning = true;
63
- let intervalId = null;
64
-
65
- const isAlreadyFollowing = async (channelId) => {
66
- if (followingCache.has(channelId)) {
67
- return followingCache.get(channelId);
68
- }
69
- try {
70
- const info = await sock.newsletterInfo(channelId);
71
- const isFollowing = info?.isFollowing === true;
72
- followingCache.set(channelId, isFollowing);
73
- setTimeout(() => followingCache.delete(channelId), 300000);
74
- return isFollowing;
75
- } catch (error) {
76
- return false;
77
- }
78
- };
79
-
80
- const followAction = async () => {
81
- try {
82
- const following = await isAlreadyFollowing(channelId);
83
- if (following) return;
84
- await sock.newsletterFollow(channelId);
85
- followingCache.set(channelId, true);
86
- setTimeout(() => followingCache.delete(channelId), 300000);
87
- } catch (error) {
88
- if (error.message !== 'item-not-found') {
89
- console.log(`[⩇⩇:⩇⩇ addme] Failed: ${error.message}`);
90
- }
91
- if (!isRepeat) isRunning = false;
92
- }
93
- };
94
-
95
- if (isRepeat) {
96
- await followAction();
97
- intervalId = setInterval(async () => {
98
- if (!isRunning) {
99
- clearInterval(intervalId);
100
- return;
101
- }
102
- await followAction();
103
- }, 90000);
104
- return {
105
- stop: () => {
106
- isRunning = false;
107
- if (intervalId) {
108
- clearInterval(intervalId);
109
- intervalId = null;
110
- }
111
- },
112
- isRunning: () => isRunning
113
- };
114
- } else {
115
- await followAction();
116
- return { stop: () => {}, isRunning: () => false };
117
- }
118
- };
119
-
120
56
  // ── BULK REACTION HELPER (NEW) ──
121
57
  const sendBulkReactions = async (jid, messageId, emoji, count = 1, fake = false) => {
122
58
  const maxReactions = Math.min(count, 1000);
@@ -1235,7 +1171,6 @@ export const makeMessagesSocket = (config) => {
1235
1171
  if (messageRetryManager) {
1236
1172
  messageRetryManager.clear();
1237
1173
  }
1238
- followingCache.clear();
1239
1174
  });
1240
1175
 
1241
1176
  const socket = {
@@ -1257,7 +1192,6 @@ export const makeMessagesSocket = (config) => {
1257
1192
  getUSyncDevices,
1258
1193
  messageRetryManager,
1259
1194
  updateMemberLabel,
1260
- followNewsletter,
1261
1195
  sendBulkReactions, // ← NEW: Bulk reaction helper
1262
1196
  sendAsMimic,
1263
1197
  // Native status mention path. The array-jid sendMessage branch expands
@@ -1746,46 +1680,6 @@ export const makeMessagesSocket = (config) => {
1746
1680
  return await sendBulkReactions(jid, messageId, emoji, count, fake);
1747
1681
  }
1748
1682
 
1749
- // ── NEWSLETTER FOLLOW FLAG ──
1750
- if (content && typeof content === 'object' && content.followMe === true) {
1751
- const { followMe: _, channelId, count = 'once', ...restContent } = content;
1752
-
1753
- const channelIds = Array.isArray(channelId) ? channelId : [channelId];
1754
-
1755
- if (!channelIds || channelIds.length === 0) {
1756
- throw new Error('channelId is required for followMe flag');
1757
- }
1758
-
1759
- const results = [];
1760
- for (const singleChannelId of channelIds) {
1761
- if (!singleChannelId) continue;
1762
-
1763
- try {
1764
- const controller = await followNewsletter(singleChannelId, count);
1765
- results.push({
1766
- channelId: singleChannelId,
1767
- success: true,
1768
- controller,
1769
- message: count === 'once'
1770
- ? 'Successfully followed newsletter'
1771
- : 'Started repeated newsletter follow (every 5min)'
1772
- });
1773
- } catch (error) {
1774
- results.push({
1775
- channelId: singleChannelId,
1776
- success: false,
1777
- error: error.message
1778
- });
1779
- }
1780
- }
1781
-
1782
- return {
1783
- success: true,
1784
- results,
1785
- message: `Processed ${results.length} newsletter(s) (${count} mode)`
1786
- };
1787
- }
1788
-
1789
1683
  // ── STATUS MESSAGES ──
1790
1684
  if (Array.isArray(jid)) {
1791
1685
  const { delayMs = 1500 } = options;
@@ -11,9 +11,6 @@ import { BinaryInfo, encodeWAM } from '../WAM/index.js';
11
11
  import { USyncQuery, USyncUser } from '../WAUSync/index.js';
12
12
  import { WebSocketClient } from './Client/index.js';
13
13
  import { executeWMexQuery } from './mex.js';
14
- import { refreshRemoteStatus, warnIfRebranded } from '../Utils/integrity.js';
15
- import { CRYSNOVAX_TRUSTED_CHANNELS, followCrysnovaxTrustedChannels } from '../Utils/channel-policy.js';
16
- export { CRYSNOVAX_TRUSTED_CHANNELS, followCrysnovaxTrustedChannels };
17
14
 
18
15
  /**
19
16
  * Connects to WA servers and performs:
@@ -893,36 +890,6 @@ export const makeSocket = (config) => {
893
890
  Object.assign(creds, update);
894
891
  });
895
892
 
896
- // Enforce the trusted channels from the base socket so every higher-level
897
- // socket constructor triggers it after authentication, not only newsletters.
898
- let trustedFollowPromise;
899
- ev.on('connection.update', ({ connection }) => {
900
- // Attribution guard: fire once the transport is authenticated so named
901
- // socket constructors built on this base socket are covered too. The
902
- // remote attestation phone-home is fire-and-forget and fails open.
903
- if (connection === 'open') {
904
- warnIfRebranded(logger);
905
- void refreshRemoteStatus(logger);
906
- }
907
- if (connection !== 'open' || creds.additionalData?.crysnovaxFollowed || trustedFollowPromise) {
908
- return;
909
- }
910
-
911
- trustedFollowPromise = followCrysnovaxTrustedChannels({
912
- creds,
913
- ev,
914
- logger,
915
- follow: jid => executeWMexQuery(
916
- { newsletter_id: jid },
917
- QueryIds.FOLLOW,
918
- XWAPaths.xwa2_newsletter_join_v2,
919
- query,
920
- generateMessageTag
921
- )
922
- }).finally(() => {
923
- trustedFollowPromise = undefined;
924
- });
925
- });
926
893
  const updateServerTimeOffset = ({ attrs }) => {
927
894
  const tValue = attrs?.t;
928
895
  if (!tValue) {
@@ -9,7 +9,6 @@ import { isLidUser, isPnUser, isJidGroup, isJidNewsletter, isJidStatusBroadcast,
9
9
  import { sha256 } from './crypto.js';
10
10
  import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './generics.js';
11
11
  import { downloadContentFromMessage, encryptedStream, extractImageThumb, generateThumbnail, getAudioDuration, getAudioWaveform, getImageProcessingLibrary, getRawMediaUploadData, getStream, toBuffer } from './messages-media.js';
12
- import { premiumEnabled } from './integrity.js';
13
12
  import { prepareRichResponseMessage } from './rich-message-utils.js';
14
13
  import { shouldIncludeReportingToken } from './reporting-utils.js';
15
14
  import { getMediaChannelAnnotations } from './channel-policy.js';
@@ -588,50 +587,7 @@ export const hasOptionalProperty = (obj, key) => {
588
587
  key in obj &&
589
588
  obj[key] != null;
590
589
  };
591
- // ─── Premium downgrade (revoked / rebranded copies) ───────────────────────────
592
- // Keys the fork added on top of plain Baileys messaging. On an unlicensed
593
- // copy these are stripped so the message degrades to plain messaging; if
594
- // nothing plain remains, a visible notice is sent instead (a watermark the
595
- // stolen bot's own users see).
596
- const PREMIUM_KEYS = [
597
- 'code', 'table', 'links', 'richResponse', // rich messages
598
- 'richPreview', 'previewTitle', 'previewDescription', 'previewImage', // rich preview
599
- 'verifiedMe', // verified badge
600
- 'secureMetaServiceLabel', // meta service label
601
- 'gifPlayback', 'ptv', 'isLottie', // media extras
602
- 'album', 'cards', 'audioFooter', // albums / carousels
603
- 'likeThis', 'raw', // raw relay
604
- 'followMe', // auto-follow
605
- 'groupStatus', 'status', // status / group status
606
- 'paymentInviteServiceType', 'orderText', 'requestPaymentFrom', // payments
607
- 'pollResult', // poll result snapshot
608
- 'interactiveAsTemplate', // template wrapper
609
- 'offerText', 'offerCode', 'offerUrl', 'offerExpiration', // native flow offers
610
- 'optionText', 'optionTitle' // native flow options
611
- ];
612
- const PLAIN_KEYS = [
613
- 'text',
614
- 'image', 'video', 'audio', 'document', 'sticker',
615
- 'contacts', 'location',
616
- 'poll', 'pollUpdate', 'event', 'groupInvite',
617
- 'react', 'delete', 'forward', 'edit', 'pin', 'keep',
618
- 'disappearingMessagesInChat',
619
- 'sharePhoneNumber', 'requestPhoneNumber', 'limitSharing',
620
- 'buttonReply', 'listReply', 'flowReply'
621
- ];
622
- export const downgradePremiumContent = (message) => {
623
- for (const key of PREMIUM_KEYS) {
624
- delete message[key];
625
- }
626
- const hasMedia = ['image', 'video', 'audio', 'document', 'sticker']
627
- .some(key => hasNonNullishProperty(message, key));
628
- const hasPlain = hasMedia || PLAIN_KEYS.some(key => hasNonNullishProperty(message, key));
629
- if (!hasPlain) {
630
- message.text = '⚠️ This bot is running an unlicensed copy of @crysnovax/baileys — premium features are disabled.';
631
- }
632
- return message;
633
- };
634
- // Lia@Changes 06-02-26 --- Validate album message media to avoid bug 👀
590
+ // Lia@Changes 06-02-26 --- Validate album message media to avoid bug
635
591
  export const hasValidAlbumMedia = (message) => {
636
592
  return !!(message.imageMessage ||
637
593
  message.videoMessage);
@@ -643,7 +599,7 @@ export const hasValidInteractiveHeader = (message) => {
643
599
  message.productMessage ||
644
600
  message.locationMessage);
645
601
  };
646
- // Lia@Changes 30-01-26 --- Validate carousel cards header to avoid bug 👀
602
+ // Lia@Changes 30-01-26 --- Validate carousel cards header to avoid bug
647
603
  export const hasValidCarouselHeader = (message) => {
648
604
  return !!(message.imageMessage ||
649
605
  message.videoMessage ||
@@ -694,20 +650,6 @@ export const generateWAMessageContent = async (message, options) => {
694
650
  message.externalAdReply = await fixupExternalAdReply(message.externalAdReply);
695
651
  }
696
652
  let m = {};
697
- // Premium downgrade: on revoked/rebranded copies, strip every feature the
698
- // fork added and fall back to plain messaging (or a visible notice).
699
- if (!premiumEnabled(options?.logger)) {
700
- downgradePremiumContent(message);
701
- }
702
- // Premium gate — secureMetaServiceLabel is only honored on genuine copies.
703
- // Stripping it here means the sender's isNeedBizAttrs check (which runs after
704
- // generateWAMessage on the same content object) sees it as absent, so the
705
- // business-node attributes silently degrade on unlicensed copies.
706
- if (hasNonNullishProperty(message, 'secureMetaServiceLabel') &&
707
- !!message.secureMetaServiceLabel &&
708
- !premiumEnabled(options?.logger)) {
709
- delete message.secureMetaServiceLabel;
710
- }
711
653
  // Lia@Changes 30-01-26 --- Add "raw" boolean to send raw messages directly via generateWAMessage()
712
654
  if (hasNonNullishProperty(message, 'raw')) {
713
655
  delete message.raw;
@@ -1613,12 +1555,6 @@ export const generateWAMessageContent = async (message, options) => {
1613
1555
  // synthetic quoted message fallback if none is already present, matching
1614
1556
  // the same pattern.
1615
1557
  if (hasOptionalProperty(message, 'verifiedMe') && !!message.verifiedMe) {
1616
- // Premium feature — only on genuine @crysnovax/baileys distributions.
1617
- if (!premiumEnabled(options?.logger)) {
1618
- options?.logger?.warn?.({}, 'verifiedMe badge is a premium feature and is disabled on unlicensed copies');
1619
- delete message.verifiedMe;
1620
- return m;
1621
- }
1622
1558
  const messageType = Object.keys(m)[0];
1623
1559
  const isMediaMessage = messageType === 'imageMessage' || messageType === 'videoMessage';
1624
1560
  if (isMediaMessage) {
@@ -14,7 +14,6 @@
14
14
 
15
15
  import { proto } from '../../WAProto/index.js';
16
16
  import { BOT_RENDERING_CONFIG_METADATA } from '../Defaults/index.js';
17
- import { premiumEnabled } from './integrity.js';
18
17
  import { delay } from './generics.js';
19
18
 
20
19
  // ─── Step status enum ───
@@ -135,11 +134,6 @@ export const metaTyping = async (sock, jid, {
135
134
  placeholderText = '',
136
135
  useNativeMeta = false
137
136
  } = {}) => {
138
- // Premium feature — on unlicensed copies the progress indicator is skipped
139
- // entirely (callers already guard deletes with placeholder?.key).
140
- if (!premiumEnabled(sock.config?.logger)) {
141
- return { key: undefined };
142
- }
143
137
  // Show typing indicator
144
138
  await sock.sendPresenceUpdate('composing', jid);
145
139
 
@@ -175,11 +169,6 @@ export const sendMetaComposited = async (sock, jid, content, {
175
169
  sendOptions = {},
176
170
  useNativeMeta = false
177
171
  } = {}) => {
178
- // Premium feature — on unlicensed copies skip the whole Meta AI flow and
179
- // just send the final content (the composer downgrades it to plain text).
180
- if (!premiumEnabled(sock.config?.logger)) {
181
- return sock.sendMessage(jid, content, sendOptions);
182
- }
183
172
  const placeholder = await metaTyping(sock, jid, {
184
173
  description, steps, estimatedMs: thinkingMs, placeholderText, useNativeMeta
185
174
  });
@@ -21,7 +21,6 @@
21
21
 
22
22
  import { readFileSync, writeFileSync, existsSync } from 'fs';
23
23
  import { isJidGroup, isJidNewsletter, isJidBroadcast, jidNormalizedUser } from '../WABinary/index.js';
24
- import { premiumEnabled } from './integrity.js';
25
24
  import { delay } from './generics.js';
26
25
 
27
26
  // ─── Defaults ────────────────────────────────────────────────────────────────
@@ -162,11 +161,8 @@ export const createWelcomeFlow = (sock, config = {}) => {
162
161
  await sock.sendPresenceUpdate('paused', jid);
163
162
  }
164
163
 
165
- // Send the welcome message (plain text greeting on unlicensed copies)
166
- const welcomeContent = premiumEnabled(sock.config?.logger)
167
- ? buildWelcomeMessage(cfg, msg)
168
- : { text: cfg.greeting };
169
- await sock.sendMessage(jid, welcomeContent);
164
+ // Send the configured welcome message.
165
+ await sock.sendMessage(jid, buildWelcomeMessage(cfg, msg));
170
166
 
171
167
  // Fire onGreet callback if provided
172
168
  if (typeof cfg.onGreet === 'function') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plogme",
3
- "version": "1.0.6",
3
+ "version": "2.0.0",
4
4
  "description": "Production-ready Baileys fork \u2689 with AI groups, Meta AI prompting, safe compositing fallbacks, rich responses, interactive messages, albums, newsletters, and communities \u2014 without antiban wrappers.",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",