nodebb-plugin-anti-account-sharing 1.0.0 → 1.0.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/library.js +61 -56
- package/package.json +1 -1
- package/plugin.json +17 -18
package/library.js
CHANGED
|
@@ -8,76 +8,81 @@ const Plugin = {};
|
|
|
8
8
|
// --- AYARLAR ---
|
|
9
9
|
const MAX_DEVICES = 1; // Kaç bilgisayara izin verilsin?
|
|
10
10
|
|
|
11
|
-
// Cihazın Mobil olup olmadığını anlayan fonksiyon
|
|
12
11
|
function isMobile(req) {
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const ua = req?.headers?.['user-agent'] || '';
|
|
13
|
+
return /Mobile|Android|iPhone|iPad|iPod/i.test(ua);
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
Plugin.init = async function (
|
|
18
|
-
|
|
16
|
+
Plugin.init = async function () {
|
|
17
|
+
console.log(`[Anti-Share] Güvenlik Aktif (Limit: ${MAX_DEVICES} Bilgisayar) 🛡️`);
|
|
19
18
|
};
|
|
20
19
|
|
|
21
|
-
// 1
|
|
20
|
+
// 1) Login olunca session'ı kaydet
|
|
22
21
|
Plugin.recordSession = async function (data) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
22
|
+
const req = data?.req;
|
|
23
|
+
const uid = data?.uid;
|
|
24
|
+
|
|
25
|
+
// req yoksa sessizce çık (bazı akışlarda gelemeyebiliyor)
|
|
26
|
+
if (!req || !uid || !req.sessionID) return;
|
|
27
|
+
|
|
28
|
+
// Mobil girişleri takip etmiyoruz
|
|
29
|
+
if (isMobile(req)) return;
|
|
30
|
+
|
|
31
|
+
const key = `antishare:sessions:${uid}`;
|
|
32
|
+
|
|
33
|
+
// Yeni oturumu sona ekle, sonra sadece son MAX_DEVICES kadarını tut
|
|
34
|
+
await db.listAppend(key, req.sessionID);
|
|
35
|
+
await db.listTrim(key, -MAX_DEVICES, -1);
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
// 2
|
|
38
|
+
// 2) Her page + api isteğinde kontrol
|
|
39
39
|
Plugin.checkSession = async function (data) {
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
const req = data?.req;
|
|
41
|
+
const res = data?.res;
|
|
42
|
+
|
|
43
|
+
if (!req || !res) return data;
|
|
44
|
+
|
|
45
|
+
// login değilse veya mobilse karışma
|
|
46
|
+
if (!req.uid || req.uid <= 0 || isMobile(req)) return data;
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
// admin ise karışma
|
|
49
|
+
const isAdmin = await user.isAdministrator(req.uid);
|
|
50
|
+
if (isAdmin) return data;
|
|
51
|
+
|
|
52
|
+
const key = `antishare:sessions:${req.uid}`;
|
|
53
|
+
const validSessions = await db.getListRange(key, 0, -1);
|
|
54
|
+
|
|
55
|
+
// liste boşsa (ilk login vs.) karışma
|
|
56
|
+
if (!Array.isArray(validSessions) || !validSessions.length) return data;
|
|
57
|
+
|
|
58
|
+
// sessionID yoksa karışma
|
|
59
|
+
if (!req.sessionID) return data;
|
|
60
|
+
|
|
61
|
+
if (!validSessions.includes(req.sessionID)) {
|
|
62
|
+
// Oturumu öldür
|
|
63
|
+
try { req.logout?.(); } catch (e) {}
|
|
64
|
+
if (req.session) {
|
|
65
|
+
try { req.session.destroy(() => {}); } catch (e) {}
|
|
46
66
|
}
|
|
47
67
|
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// Oturumu Öldür
|
|
61
|
-
req.logout();
|
|
62
|
-
if (req.session) req.session.destroy();
|
|
63
|
-
|
|
64
|
-
if (req.xhr || (req.headers.accept && req.headers.accept.indexOf('json') > -1)) {
|
|
65
|
-
return res.status(401).json({
|
|
66
|
-
error: 'session_terminated',
|
|
67
|
-
message: 'Maksimum cihaz sınırına ulaşıldı.'
|
|
68
|
-
});
|
|
69
|
-
} else {
|
|
70
|
-
return res.redirect('/login?error=session-conflict');
|
|
71
|
-
}
|
|
68
|
+
const wantsJson =
|
|
69
|
+
req.xhr ||
|
|
70
|
+
(req.headers.accept && req.headers.accept.includes('json')) ||
|
|
71
|
+
req.originalUrl?.startsWith('/api/');
|
|
72
|
+
|
|
73
|
+
if (wantsJson) {
|
|
74
|
+
res.status(401).json({
|
|
75
|
+
error: 'session_terminated',
|
|
76
|
+
message: 'Maksimum cihaz sınırına ulaşıldı.',
|
|
77
|
+
});
|
|
78
|
+
return; // IMPORTANT: response bitti
|
|
72
79
|
}
|
|
73
80
|
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
res.redirect('/login?error=session-conflict');
|
|
82
|
+
return; // IMPORTANT: response bitti
|
|
83
|
+
}
|
|
76
84
|
|
|
77
|
-
|
|
78
|
-
Plugin.addScripts = async function (scripts) {
|
|
79
|
-
scripts.push('plugins/nodebb-plugin-anti-account-sharing/static/security.js');
|
|
80
|
-
return scripts;
|
|
85
|
+
return data;
|
|
81
86
|
};
|
|
82
87
|
|
|
83
|
-
module.exports = Plugin;
|
|
88
|
+
module.exports = Plugin;
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
2
|
+
"id": "nodebb-plugin-anti-account-sharing",
|
|
3
|
+
"name": "Anti-Share Security",
|
|
4
|
+
"description": "Bilgisayar oturumlarını tekilleştirerek hesap paylaşımını engeller (Mobil hariç).",
|
|
5
|
+
"library": "./library.js",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{ "hook": "static:app.load", "method": "init" },
|
|
8
|
+
{ "hook": "action:user.loggedIn", "method": "recordSession" },
|
|
9
|
+
{ "hook": "filter:router.page", "method": "checkSession" },
|
|
10
|
+
{ "hook": "filter:router.api", "method": "checkSession" }
|
|
11
|
+
],
|
|
12
|
+
"scripts": [
|
|
13
|
+
"static/security.js"
|
|
14
|
+
],
|
|
15
|
+
"staticDirs": {
|
|
16
|
+
"static": "./static"
|
|
17
|
+
}
|
|
18
|
+
}
|