magpie-plugin-loomy-auth 0.1.8 → 0.1.9
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 +3 -2
- package/docs/internals.md +22 -10
- package/index.mjs +10 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,8 +99,9 @@ Loomy 的邀请奖励:**邀请好友双方各得 5000 积分**(实测,附
|
|
|
99
99
|
你只要照常把新账号登进 magpie,下一次签到时会自动:查本机其它账号的邀请码 →
|
|
100
100
|
挑一个 → 兑换。新号 +5000,老号 +5000。
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
每条邀请码能邀请 1000 人;**每个号只能被邀请一次**,所以「A 邀 B、B 再邀 A」
|
|
103
|
+
平台是允许的(实测过,服务端不拦)。插件不干预这个 —— 它只守平台自己的那条:
|
|
104
|
+
本号已经被邀请过就不再兑换。
|
|
104
105
|
|
|
105
106
|
---
|
|
106
107
|
|
package/docs/internals.md
CHANGED
|
@@ -175,21 +175,33 @@ E4DPT6 usedCount 0 → 1 181 activation false → true
|
|
|
175
175
|
|
|
176
176
|
②③ 失败都不影响签到结果 —— 它们是顺带做的事,不是前置条件。
|
|
177
177
|
|
|
178
|
-
####
|
|
178
|
+
#### 判据只有一条:本号是否已经被邀请过
|
|
179
179
|
|
|
180
|
-
|
|
180
|
+
平台规则:**每个账号仅能兑换一次**(客户端文案「你已经兑换过积分啦」)。
|
|
181
|
+
所以判断依据就是 `GET /points/activation` 的 `activated`,跟「谁邀请了谁」无关。
|
|
182
|
+
|
|
183
|
+
**为什么不需要知道对方是谁**:`GET /api/v1/invitation-codes` 只回
|
|
184
|
+
`{inviteCode, usedCount, maxUses, status}` —— 有数量、没有名单。
|
|
185
|
+
客户端里也没有「被邀请的好友」列表接口;探测 `/invitation-codes/invitees`、
|
|
186
|
+
`/invitation-records`、`/points/invitation-records` 全部 404。
|
|
187
|
+
既然拿不到,就不该假装能判断。
|
|
188
|
+
|
|
189
|
+
#### 平台**允许**互刷(实测,不是推测)
|
|
181
190
|
|
|
182
191
|
```
|
|
183
|
-
189
|
|
184
|
-
181
|
|
185
|
-
|
|
186
|
-
⇒ 各得 10000
|
|
192
|
+
189 兑换 181 的 FDW3CU → +5000 填写邀请码奖励
|
|
193
|
+
181 兑换 189 的 E4DPT6 → +5000 填写邀请码奖励
|
|
194
|
+
两边各再收 +5000 邀请好友奖励
|
|
195
|
+
⇒ 各得 10000,服务端全程 200,没有任何拦截
|
|
187
196
|
```
|
|
188
197
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
198
|
+
**这是平台的规则漏洞,不是插件的责任。** 本插件只做两件合规的事:
|
|
199
|
+
|
|
200
|
+
1. 本号 `activated: true` 时不再兑换(平台规则);
|
|
201
|
+
2. 把本号自己的码从候选里排除(不能自己邀请自己)。
|
|
202
|
+
|
|
203
|
+
⚠ 曾经加过一条「本号码被用过就不再兑换别人的码」的规则,**已移除** —— 它拦不住互刷
|
|
204
|
+
(先兑换的一方 `usedCount` 还是 0),却会误伤 A→B→C 这种正常长链里的 B。
|
|
193
205
|
|
|
194
206
|
#### 候选从哪来
|
|
195
207
|
|
package/index.mjs
CHANGED
|
@@ -179,17 +179,23 @@ export const LoomyAuthPlugin = async ({ client, directory } = {}) => {
|
|
|
179
179
|
* 平台侧可能视作互刷。
|
|
180
180
|
*/
|
|
181
181
|
const pickInviteFor = async (session) => {
|
|
182
|
-
//
|
|
182
|
+
// ① **判据只有一条:本号是否已经被邀请过。**
|
|
183
|
+
//
|
|
184
|
+
// 平台规则就这一条(客户端文案:「每个账号仅能兑换一次」「你已经兑换过积分啦」)。
|
|
185
|
+
// 所以不需要知道「谁邀请了谁」—— 那信息接口根本不提供
|
|
186
|
+
// (`invitation-codes` 只回 `usedCount` 这个数量,不说是谁)。
|
|
187
|
+
// `appliedInvitationCode` 只用于日志,不参与判断。
|
|
183
188
|
let applied
|
|
184
189
|
try {
|
|
185
190
|
const st = await fetchActivation(session)
|
|
186
191
|
if (st.activated) return undefined
|
|
187
192
|
applied = st.appliedInvitationCode
|
|
188
193
|
} catch {
|
|
194
|
+
// 读不到状态就别乱兑换 —— 宁可这一天不换
|
|
189
195
|
return undefined
|
|
190
196
|
}
|
|
191
197
|
|
|
192
|
-
//
|
|
198
|
+
// ② 本号自己的码要从候选里排除(不能自己邀请自己)
|
|
193
199
|
let selfCode
|
|
194
200
|
try {
|
|
195
201
|
const mine = await fetchInviteCodes(session)
|
|
@@ -198,35 +204,11 @@ export const LoomyAuthPlugin = async ({ client, directory } = {}) => {
|
|
|
198
204
|
selfCode = undefined
|
|
199
205
|
}
|
|
200
206
|
|
|
201
|
-
//
|
|
202
|
-
// 那用它的那个人反过来又能拿本号的码 —— 两个号互相邀请、各拿两笔
|
|
203
|
-
// 5000,就是刷。实测踩到过:189 与 181 互相兑换,各得 10000。
|
|
204
|
-
//
|
|
205
|
-
// 判据不靠猜:本机每张码的 `usedCount` 就是「被几个人用过」。
|
|
206
|
-
// 只要本号自己的码 `usedCount > 0`,说明有人邀请过本号这边的关系,
|
|
207
|
-
// 此时**已经兑换过就别再换**(上面 `activated` 已拦住),
|
|
208
|
-
// 而本号自己的码继续留给**新来的号**用 —— 单向,不成环。
|
|
209
|
-
//
|
|
210
|
-
// 更严格的一层:把「已经用掉本号码的那些账号的码」也排除。
|
|
211
|
-
// 但 `usedCount` 只给数量、不给是谁,所以能做到的就是:
|
|
212
|
-
// **本号码一旦被用过,就再也不用别人的码**(互刷必然要求双方各用一次)。
|
|
213
|
-
let selfUsed = 0
|
|
214
|
-
try {
|
|
215
|
-
const mine = await fetchInviteCodes(session)
|
|
216
|
-
selfUsed = mine[0]?.usedCount ?? 0
|
|
217
|
-
} catch {
|
|
218
|
-
selfUsed = 0
|
|
219
|
-
}
|
|
220
|
-
if (selfUsed > 0) {
|
|
221
|
-
log(`本号的邀请码已被 ${selfUsed} 人使用,不再兑换别人的码(避免互刷)`)
|
|
222
|
-
return undefined
|
|
223
|
-
}
|
|
224
|
-
|
|
207
|
+
// ③ 从本机**别的账号**的码里挑一个还有余量的
|
|
225
208
|
const candidates = await collectInviteCandidates(session)
|
|
226
209
|
const picked = _pure.pickInviteCode(candidates, selfCode)
|
|
227
210
|
if (!picked) return undefined
|
|
228
|
-
//
|
|
229
|
-
if (applied && picked.code === applied) return undefined
|
|
211
|
+
if (applied && picked.code === applied) return undefined // 理论上不可达,防御性保留
|
|
230
212
|
return picked.code
|
|
231
213
|
}
|
|
232
214
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "magpie-plugin-loomy-auth",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Loomy (iFlytek) for magpie: desktop-session import / SMS / session sign-in, live model catalog with reasoning efforts, chat with tools and images, and the two credit pools reported as the host routes them — the daily pool counts, the permanent one is shown aside.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.mjs",
|