+3
-4
src/agent.ts
+3
-4
src/agent.ts
···
1
-
import { AtpAgent } from "@atproto/api";
2
-
3
-
import { setGlobalDispatcher, Agent as Agent } from "undici";
1
+
import { AtpAgent } from '@atproto/api';
2
+
import { setGlobalDispatcher, Agent as Agent } from 'undici';
4
3
5
4
setGlobalDispatcher(new Agent({ connect: { timeout: 20_000 } }));
6
-
import { BSKY_HANDLE, BSKY_PASSWORD, OZONE_PDS } from "./config.js";
5
+
import { BSKY_HANDLE, BSKY_PASSWORD, OZONE_PDS } from './config.js';
7
6
8
7
export const agent = new AtpAgent({
9
8
service: `https://${OZONE_PDS}`,
+46
-41
src/checkHandles.ts
+46
-41
src/checkHandles.ts
···
11
11
handle: string,
12
12
time: number,
13
13
) => {
14
-
// Get a list of labels
15
-
const labels: string[] = Array.from(
16
-
HANDLE_CHECKS,
17
-
(handleCheck) => handleCheck.label,
18
-
);
19
-
20
-
// iterate through the labels
21
-
labels.forEach((label) => {
22
-
const checkList = HANDLE_CHECKS.find(
23
-
(handleCheck) => handleCheck.label === label,
14
+
try {
15
+
// Get a list of labels
16
+
const labels: string[] = Array.from(
17
+
HANDLE_CHECKS,
18
+
(handleCheck) => handleCheck.label,
24
19
);
25
20
26
-
if (checkList?.ignoredDIDs) {
27
-
if (checkList.ignoredDIDs.includes(did)) {
28
-
logger.info(`Whitelisted DID: ${did}`);
29
-
return;
30
-
}
31
-
}
21
+
// iterate through the labels
22
+
labels.forEach((label) => {
23
+
const checkList = HANDLE_CHECKS.find(
24
+
(handleCheck) => handleCheck.label === label,
25
+
);
32
26
33
-
if (checkList!.check.test(handle)) {
34
-
// False-positive checks
35
-
if (checkList?.whitelist) {
36
-
if (checkList?.whitelist.test(handle)) {
37
-
logger.info(`Whitelisted phrase found for: ${handle}`);
27
+
if (checkList?.ignoredDIDs) {
28
+
if (checkList.ignoredDIDs.includes(did)) {
29
+
logger.info(`Whitelisted DID: ${did}`);
38
30
return;
39
31
}
40
32
}
41
33
42
-
if (checkList?.toLabel === true) {
43
-
logger.info(`[CHECKHANDLE]: Labeling ${did} for ${checkList!.label}`);
44
-
{
45
-
createAccountLabel(
46
-
did,
47
-
`${checkList!.label}`,
48
-
`${time}: ${checkList!.comment} - ${handle}`,
49
-
);
34
+
if (checkList!.check.test(handle)) {
35
+
// False-positive checks
36
+
if (checkList?.whitelist) {
37
+
if (checkList?.whitelist.test(handle)) {
38
+
logger.info(`Whitelisted phrase found for: ${handle}`);
39
+
return;
40
+
}
41
+
}
42
+
43
+
if (checkList?.toLabel === true) {
44
+
logger.info(`[CHECKHANDLE]: Labeling ${did} for ${checkList.label}`);
45
+
{
46
+
createAccountLabel(
47
+
did,
48
+
checkList.label,
49
+
`${time}: ${checkList.comment} - ${handle}`,
50
+
);
51
+
}
50
52
}
51
-
}
52
53
53
-
if (checkList?.reportAcct === true) {
54
-
logger.info(`[CHECKHANDLE]: Reporting ${did} for ${checkList!.label}`);
55
-
createAccountReport(did, `${time}: ${checkList!.comment} - ${handle}`);
56
-
}
54
+
if (checkList?.reportAcct === true) {
55
+
logger.info(`[CHECKHANDLE]: Reporting ${did} for ${checkList.label}`);
56
+
createAccountReport(did, `${time}: ${checkList.comment} - ${handle}`);
57
+
}
57
58
58
-
if (checkList?.commentAcct === true) {
59
-
logger.info(
60
-
`[CHECKHANDLE]: Commenting on ${did} for ${checkList!.label}`,
61
-
);
62
-
createAccountComment(did, `${time}: ${checkList!.comment} - ${handle}`);
59
+
if (checkList?.commentAcct === true) {
60
+
logger.info(
61
+
`[CHECKHANDLE]: Commenting on ${did} for ${checkList.label}`,
62
+
);
63
+
createAccountComment(did, `${time}: ${checkList.comment} - ${handle}`);
64
+
}
63
65
}
64
-
}
65
-
});
66
+
});
67
+
} catch (error) {
68
+
logger.error(`Error in checkHandle for ${did}:`, error);
69
+
throw error;
70
+
}
66
71
};
+94
-89
src/checkPosts.ts
+94
-89
src/checkPosts.ts
···
10
10
import { getFinalUrl, getLanguage } from './utils.js';
11
11
12
12
export const checkPosts = async (post: Post[]) => {
13
-
// Get a list of labels
14
-
const labels: string[] = Array.from(
15
-
POST_CHECKS,
16
-
(postCheck) => postCheck.label,
17
-
);
13
+
try {
14
+
// Get a list of labels
15
+
const labels: string[] = Array.from(
16
+
POST_CHECKS,
17
+
(postCheck) => postCheck.label,
18
+
);
18
19
19
-
const urlRegex = /https?:\/\/[^\s]+/g;
20
+
const urlRegex = /https?:\/\/[^\s]+/g;
20
21
21
-
// Check for link shorteners
22
-
if (LINK_SHORTENER.test(post[0].text)) {
23
-
try {
24
-
const url = post[0].text.match(urlRegex);
25
-
if (url && LINK_SHORTENER.test(url[0])) {
26
-
logger.info(`[CHECKPOSTS]: Checking shortened URL: ${url[0]}`);
27
-
const finalUrl = await getFinalUrl(url[0]);
28
-
if (finalUrl) {
29
-
const originalUrl = post[0].text;
30
-
post[0].text = post[0].text.replace(url[0], finalUrl);
31
-
logger.info(
32
-
`[CHECKPOSTS]: Shortened URL resolved: ${originalUrl} -> ${finalUrl}`,
33
-
);
22
+
// Check for link shorteners
23
+
if (LINK_SHORTENER.test(post[0].text)) {
24
+
try {
25
+
const url = post[0].text.match(urlRegex);
26
+
if (url && LINK_SHORTENER.test(url[0])) {
27
+
logger.info(`[CHECKPOSTS]: Checking shortened URL: ${url[0]}`);
28
+
const finalUrl = await getFinalUrl(url[0]);
29
+
if (finalUrl) {
30
+
const originalUrl = post[0].text;
31
+
post[0].text = post[0].text.replace(url[0], finalUrl);
32
+
logger.info(
33
+
`[CHECKPOSTS]: Shortened URL resolved: ${originalUrl} -> ${finalUrl}`,
34
+
);
35
+
}
34
36
}
35
-
}
36
-
} catch (error) {
37
-
logger.error(
38
-
`[CHECKPOSTS]: Failed to resolve shortened URL: ${post[0].text}`,
39
-
error,
40
-
);
37
+
} catch (error) {
38
+
logger.error(
39
+
`[CHECKPOSTS]: Failed to resolve shortened URL: ${post[0].text}`,
40
+
error,
41
+
);
41
42
// Keep the original URL if resolution fails
43
+
}
42
44
}
43
-
}
44
45
45
-
// Get the post's language
46
-
const lang = await getLanguage(post[0].text);
46
+
// Get the post's language
47
+
const lang = await getLanguage(post[0].text);
47
48
48
-
// iterate through the labels
49
-
labels.forEach((label) => {
50
-
const checkPost = POST_CHECKS.find(
51
-
(postCheck) => postCheck.label === label,
52
-
);
49
+
// iterate through the labels
50
+
labels.forEach((label) => {
51
+
const checkPost = POST_CHECKS.find(
52
+
(postCheck) => postCheck.label === label,
53
+
);
53
54
54
-
if (checkPost?.language || checkPost?.language !== undefined) {
55
-
if (!checkPost?.language.includes(lang)) {
56
-
return;
55
+
if (checkPost?.language || checkPost?.language !== undefined) {
56
+
if (!checkPost?.language.includes(lang)) {
57
+
return;
58
+
}
57
59
}
58
-
}
59
60
60
-
if (checkPost?.ignoredDIDs) {
61
-
if (checkPost?.ignoredDIDs.includes(post[0].did)) {
62
-
logger.info(`[CHECKPOSTS]: Whitelisted DID: ${post[0].did}`);
63
-
return;
61
+
if (checkPost?.ignoredDIDs) {
62
+
if (checkPost?.ignoredDIDs.includes(post[0].did)) {
63
+
logger.info(`[CHECKPOSTS]: Whitelisted DID: ${post[0].did}`);
64
+
return;
65
+
}
64
66
}
65
-
}
66
67
67
-
if (checkPost!.check.test(post[0].text)) {
68
+
if (checkPost!.check.test(post[0].text)) {
68
69
// Check if post is whitelisted
69
-
if (checkPost?.whitelist) {
70
-
if (checkPost?.whitelist.test(post[0].text)) {
71
-
logger.info('[CHECKPOSTS]: Whitelisted phrase found"');
72
-
return;
70
+
if (checkPost?.whitelist) {
71
+
if (checkPost?.whitelist.test(post[0].text)) {
72
+
logger.info('[CHECKPOSTS]: Whitelisted phrase found"');
73
+
return;
74
+
}
73
75
}
74
-
}
75
76
76
-
if (checkPost!.toLabel === true) {
77
-
logger.info(
78
-
`[CHECKPOSTS]: Labeling ${post[0].atURI} for ${checkPost!.label}`,
79
-
);
80
-
createPostLabel(
81
-
post[0].atURI,
82
-
post[0].cid,
83
-
`${checkPost!.label}`,
84
-
`${post[0].time}: ${checkPost!.comment} at ${post[0].atURI} with text "${post[0].text}"`,
85
-
);
86
-
}
77
+
if (checkPost!.toLabel) {
78
+
logger.info(
79
+
`[CHECKPOSTS]: Labeling ${post[0].atURI} for ${checkPost!.label}`,
80
+
);
81
+
createPostLabel(
82
+
post[0].atURI,
83
+
post[0].cid,
84
+
checkPost!.label,
85
+
`${post[0].time}: ${checkPost!.comment} at ${post[0].atURI} with text "${post[0].text}"`,
86
+
);
87
+
}
87
88
88
-
if (checkPost!.reportPost === true) {
89
-
logger.info(
90
-
`[CHECKPOSTS]: Reporting ${post[0].atURI} for ${checkPost!.label}`,
91
-
);
92
-
logger.info(`Reporting: ${post[0].atURI}`);
93
-
createPostReport(
94
-
post[0].atURI,
95
-
post[0].cid,
96
-
`${post[0].time}: ${checkPost!.comment} at ${post[0].atURI} with text "${post[0].text}"`,
97
-
);
98
-
}
89
+
if (checkPost!.reportPost === true) {
90
+
logger.info(
91
+
`[CHECKPOSTS]: Reporting ${post[0].atURI} for ${checkPost!.label}`,
92
+
);
93
+
logger.info(`Reporting: ${post[0].atURI}`);
94
+
createPostReport(
95
+
post[0].atURI,
96
+
post[0].cid,
97
+
`${post[0].time}: ${checkPost!.comment} at ${post[0].atURI} with text "${post[0].text}"`,
98
+
);
99
+
}
99
100
100
-
if (checkPost!.reportAcct === true) {
101
-
logger.info(
102
-
`[CHECKPOSTS]: Reporting on ${post[0].did} for ${checkPost!.label} in ${post[0].atURI}`,
103
-
);
104
-
createAccountReport(
105
-
post[0].did,
106
-
`${post[0].time}: ${checkPost?.comment} at ${post[0].atURI} with text "${post[0].text}"`,
107
-
);
108
-
}
101
+
if (checkPost!.reportAcct) {
102
+
logger.info(
103
+
`[CHECKPOSTS]: Reporting on ${post[0].did} for ${checkPost!.label} in ${post[0].atURI}`,
104
+
);
105
+
createAccountReport(
106
+
post[0].did,
107
+
`${post[0].time}: ${checkPost?.comment} at ${post[0].atURI} with text "${post[0].text}"`,
108
+
);
109
+
}
109
110
110
-
if (checkPost!.commentAcct === true) {
111
-
logger.info(
112
-
`[CHECKPOSTS]: Commenting on ${post[0].did} for ${checkPost!.label} in ${post[0].atURI}`,
113
-
);
114
-
createAccountComment(
115
-
post[0].did,
116
-
`${post[0].time}: ${checkPost?.comment} at ${post[0].atURI} with text "${post[0].text}"`,
117
-
);
111
+
if (checkPost!.commentAcct) {
112
+
logger.info(
113
+
`[CHECKPOSTS]: Commenting on ${post[0].did} for ${checkPost!.label} in ${post[0].atURI}`,
114
+
);
115
+
createAccountComment(
116
+
post[0].did,
117
+
`${post[0].time}: ${checkPost?.comment} at ${post[0].atURI} with text "${post[0].text}"`,
118
+
);
119
+
}
118
120
}
119
-
}
120
-
});
121
+
});
122
+
} catch (error) {
123
+
logger.error(`Error in checkPosts for ${post[0]?.did}:`, error);
124
+
throw error;
125
+
}
121
126
};
+125
-115
src/checkProfiles.ts
+125
-115
src/checkProfiles.ts
···
14
14
displayName: string,
15
15
description: string,
16
16
) => {
17
-
const lang = await getLanguage(description);
17
+
try {
18
+
const lang = await getLanguage(description);
18
19
19
-
const labels: string[] = Array.from(
20
-
PROFILE_CHECKS,
21
-
(profileCheck) => profileCheck.label,
22
-
);
23
-
24
-
// iterate through the labels
25
-
labels.forEach((label) => {
26
-
const checkProfiles = PROFILE_CHECKS.find(
27
-
(profileCheck) => profileCheck.label === label,
20
+
const labels: string[] = Array.from(
21
+
PROFILE_CHECKS,
22
+
(profileCheck) => profileCheck.label,
28
23
);
29
24
30
-
if (checkProfiles?.language || checkProfiles?.language !== undefined) {
31
-
if (!checkProfiles?.language.includes(lang)) {
32
-
return;
25
+
// iterate through the labels
26
+
labels.forEach((label) => {
27
+
const checkProfiles = PROFILE_CHECKS.find(
28
+
(profileCheck) => profileCheck.label === label,
29
+
);
30
+
31
+
if (checkProfiles?.language || checkProfiles?.language !== undefined) {
32
+
if (!checkProfiles?.language.includes(lang)) {
33
+
return;
34
+
}
33
35
}
34
-
}
35
36
36
-
// Check if DID is whitelisted
37
-
if (checkProfiles?.ignoredDIDs) {
38
-
if (checkProfiles.ignoredDIDs.includes(did)) {
39
-
logger.info(`[CHECKDESCRIPTION]: Whitelisted DID: ${did}`);
40
-
return;
37
+
// Check if DID is whitelisted
38
+
if (checkProfiles?.ignoredDIDs) {
39
+
if (checkProfiles.ignoredDIDs.includes(did)) {
40
+
logger.info(`[CHECKDESCRIPTION]: Whitelisted DID: ${did}`);
41
+
return;
42
+
}
41
43
}
42
-
}
43
44
44
-
if (description) {
45
-
if (checkProfiles?.description === true) {
46
-
if (checkProfiles!.check.test(description)) {
45
+
if (description) {
46
+
if (checkProfiles?.description === true) {
47
+
if (checkProfiles.check.test(description)) {
47
48
// Check if description is whitelisted
48
-
if (checkProfiles!.whitelist) {
49
-
if (checkProfiles!.whitelist.test(description)) {
50
-
logger.info('[CHECKDESCRIPTION]: Whitelisted phrase found.');
51
-
return;
49
+
if (checkProfiles.whitelist) {
50
+
if (checkProfiles.whitelist.test(description)) {
51
+
logger.info('[CHECKDESCRIPTION]: Whitelisted phrase found.');
52
+
return;
53
+
}
52
54
}
53
-
}
54
55
55
-
if (checkProfiles!.toLabel === true) {
56
-
createAccountLabel(
57
-
did,
58
-
`${checkProfiles!.label}`,
59
-
`${time}: ${checkProfiles!.comment} - ${displayName} - ${description}`,
60
-
);
61
-
logger.info(
62
-
`[CHECKDESCRIPTION]: Labeling ${did} for ${checkProfiles!.label}`,
63
-
);
64
-
}
56
+
if (checkProfiles.toLabel) {
57
+
createAccountLabel(
58
+
did,
59
+
checkProfiles.label,
60
+
`${time}: ${checkProfiles.comment} - ${displayName} - ${description}`,
61
+
);
62
+
logger.info(
63
+
`[CHECKDESCRIPTION]: Labeling ${did} for ${checkProfiles.label}`,
64
+
);
65
+
}
65
66
66
-
if (checkProfiles!.reportAcct === true) {
67
-
createAccountReport(
68
-
did,
69
-
`${time}: ${checkProfiles!.comment} - ${displayName} - ${description}`,
70
-
);
71
-
logger.info(
72
-
`[CHECKDESCRIPTION]: Reporting ${did} for ${checkProfiles!.label}`,
73
-
);
74
-
}
67
+
if (checkProfiles.reportAcct) {
68
+
createAccountReport(
69
+
did,
70
+
`${time}: ${checkProfiles.comment} - ${displayName} - ${description}`,
71
+
);
72
+
logger.info(
73
+
`[CHECKDESCRIPTION]: Reporting ${did} for ${checkProfiles.label}`,
74
+
);
75
+
}
75
76
76
-
if (checkProfiles!.commentAcct === true) {
77
-
createAccountComment(
78
-
did,
79
-
`${time}: ${checkProfiles!.comment} - ${displayName} - ${description}`,
80
-
);
81
-
logger.info(
82
-
`[CHECKDESCRIPTION]: Commenting on ${did} for ${checkProfiles!.label}`,
83
-
);
77
+
if (checkProfiles.commentAcct) {
78
+
createAccountComment(
79
+
did,
80
+
`${time}: ${checkProfiles.comment} - ${displayName} - ${description}`,
81
+
);
82
+
logger.info(
83
+
`[CHECKDESCRIPTION]: Commenting on ${did} for ${checkProfiles.label}`,
84
+
);
85
+
}
84
86
}
85
87
}
86
88
}
87
-
}
88
-
});
89
+
});
90
+
} catch (error) {
91
+
logger.error(`Error in checkDescription for ${did}:`, error);
92
+
throw error;
93
+
}
89
94
};
90
95
91
96
export const checkDisplayName = async (
···
94
99
displayName: string,
95
100
description: string,
96
101
) => {
97
-
const lang = await getLanguage(description);
102
+
try {
103
+
const lang = await getLanguage(description);
98
104
99
-
// Get a list of labels
100
-
const labels: string[] = Array.from(
101
-
PROFILE_CHECKS,
102
-
(profileCheck) => profileCheck.label,
103
-
);
104
-
105
-
// iterate through the labels
106
-
labels.forEach((label) => {
107
-
const checkProfiles = PROFILE_CHECKS.find(
108
-
(profileCheck) => profileCheck.label === label,
105
+
// Get a list of labels
106
+
const labels: string[] = Array.from(
107
+
PROFILE_CHECKS,
108
+
(profileCheck) => profileCheck.label,
109
109
);
110
110
111
-
if (checkProfiles?.language || checkProfiles?.language !== undefined) {
112
-
if (!checkProfiles?.language.includes(lang)) {
113
-
return;
111
+
// iterate through the labels
112
+
labels.forEach((label) => {
113
+
const checkProfiles = PROFILE_CHECKS.find(
114
+
(profileCheck) => profileCheck.label === label,
115
+
);
116
+
117
+
if (checkProfiles?.language || checkProfiles?.language !== undefined) {
118
+
if (!checkProfiles?.language.includes(lang)) {
119
+
return;
120
+
}
114
121
}
115
-
}
116
122
117
-
// Check if DID is whitelisted
118
-
if (checkProfiles?.ignoredDIDs) {
119
-
if (checkProfiles.ignoredDIDs.includes(did)) {
120
-
logger.info(`[CHECKDISPLAYNAME]: Whitelisted DID: ${did}`);
121
-
return;
123
+
// Check if DID is whitelisted
124
+
if (checkProfiles?.ignoredDIDs) {
125
+
if (checkProfiles.ignoredDIDs.includes(did)) {
126
+
logger.info(`[CHECKDISPLAYNAME]: Whitelisted DID: ${did}`);
127
+
return;
128
+
}
122
129
}
123
-
}
124
130
125
-
if (displayName) {
126
-
if (checkProfiles?.displayName === true) {
127
-
if (checkProfiles!.check.test(displayName)) {
131
+
if (displayName) {
132
+
if (checkProfiles?.displayName === true) {
133
+
if (checkProfiles.check.test(displayName)) {
128
134
// Check if displayName is whitelisted
129
-
if (checkProfiles!.whitelist) {
130
-
if (checkProfiles!.whitelist.test(displayName)) {
131
-
logger.info('[CHECKDISPLAYNAME]: Whitelisted phrase found.');
132
-
return;
135
+
if (checkProfiles.whitelist) {
136
+
if (checkProfiles.whitelist.test(displayName)) {
137
+
logger.info('[CHECKDISPLAYNAME]: Whitelisted phrase found.');
138
+
return;
139
+
}
133
140
}
134
-
}
135
141
136
-
if (checkProfiles!.toLabel === true) {
137
-
createAccountLabel(
138
-
did,
139
-
`${checkProfiles!.label}`,
140
-
`${time}: ${checkProfiles!.comment} - ${displayName} - ${description}`,
141
-
);
142
-
logger.info(
143
-
`[CHECKDISPLAYNAME]: Labeling ${did} for ${checkProfiles!.label}`,
144
-
);
145
-
}
142
+
if (checkProfiles.toLabel) {
143
+
createAccountLabel(
144
+
did,
145
+
checkProfiles.label,
146
+
`${time}: ${checkProfiles.comment} - ${displayName} - ${description}`,
147
+
);
148
+
logger.info(
149
+
`[CHECKDISPLAYNAME]: Labeling ${did} for ${checkProfiles.label}`,
150
+
);
151
+
}
146
152
147
-
if (checkProfiles!.reportAcct === true) {
148
-
createAccountReport(
149
-
did,
150
-
`${time}: ${checkProfiles!.comment} - ${displayName} - ${description}`,
151
-
);
152
-
logger.info(
153
-
`[CHECKDISPLAYNAME]: Reporting ${did} for ${checkProfiles!.label}`,
154
-
);
155
-
}
153
+
if (checkProfiles.reportAcct) {
154
+
createAccountReport(
155
+
did,
156
+
`${time}: ${checkProfiles.comment} - ${displayName} - ${description}`,
157
+
);
158
+
logger.info(
159
+
`[CHECKDISPLAYNAME]: Reporting ${did} for ${checkProfiles.label}`,
160
+
);
161
+
}
156
162
157
-
if (checkProfiles!.commentAcct === true) {
158
-
createAccountComment(
159
-
did,
160
-
`${time}: ${checkProfiles!.comment} - ${displayName} - ${description}`,
161
-
);
162
-
logger.info(
163
-
`[CHECKDISPLAYNAME]: Commenting on ${did} for ${checkProfiles!.label}`,
164
-
);
163
+
if (checkProfiles.commentAcct) {
164
+
createAccountComment(
165
+
did,
166
+
`${time}: ${checkProfiles.comment} - ${displayName} - ${description}`,
167
+
);
168
+
logger.info(
169
+
`[CHECKDISPLAYNAME]: Commenting on ${did} for ${checkProfiles.label}`,
170
+
);
171
+
}
165
172
}
166
173
}
167
174
}
168
-
}
169
-
});
175
+
});
176
+
} catch (error) {
177
+
logger.error(`Error in checkDisplayName for ${did}:`, error);
178
+
throw error;
179
+
}
170
180
};
+77
-67
src/checkStarterPack.ts
+77
-67
src/checkStarterPack.ts
···
11
11
time: number,
12
12
atURI: string,
13
13
) => {
14
-
// Get a list of labels
15
-
const labels: string[] = Array.from(
16
-
PROFILE_CHECKS,
17
-
(profileCheck) => profileCheck.label,
18
-
);
19
-
20
-
// iterate through the labels
21
-
labels.forEach((label) => {
22
-
const checkProfiles = PROFILE_CHECKS.find(
23
-
(profileCheck) => profileCheck.label === label,
14
+
try {
15
+
// Get a list of labels
16
+
const labels: string[] = Array.from(
17
+
PROFILE_CHECKS,
18
+
(profileCheck) => profileCheck.label,
24
19
);
25
20
26
-
// Check if DID is whitelisted
27
-
if (checkProfiles?.ignoredDIDs) {
28
-
if (checkProfiles.ignoredDIDs.includes(did)) {
29
-
logger.info(`Whitelisted DID: ${did}`); return;
21
+
// iterate through the labels
22
+
labels.forEach((label) => {
23
+
const checkProfiles = PROFILE_CHECKS.find(
24
+
(profileCheck) => profileCheck.label === label,
25
+
);
26
+
27
+
// Check if DID is whitelisted
28
+
if (checkProfiles?.ignoredDIDs) {
29
+
if (checkProfiles.ignoredDIDs.includes(did)) {
30
+
logger.info(`Whitelisted DID: ${did}`); return;
31
+
}
30
32
}
31
-
}
32
33
33
-
if (atURI) {
34
-
if (checkProfiles?.starterPacks) {
35
-
if (checkProfiles?.starterPacks.includes(atURI)) {
36
-
logger.info(`Account joined via starter pack at: ${atURI}`);
37
-
createAccountLabel(
38
-
did,
39
-
`${checkProfiles!.label}`,
40
-
`${time}: ${checkProfiles!.comment} - Account joined via starter pack at: ${atURI}`,
41
-
);
34
+
if (atURI) {
35
+
if (checkProfiles?.starterPacks) {
36
+
if (checkProfiles?.starterPacks.includes(atURI)) {
37
+
logger.info(`Account joined via starter pack at: ${atURI}`);
38
+
createAccountLabel(
39
+
did,
40
+
checkProfiles.label,
41
+
`${time}: ${checkProfiles.comment} - Account joined via starter pack at: ${atURI}`,
42
+
);
43
+
}
42
44
}
43
45
}
44
-
}
45
-
});
46
+
});
47
+
} catch (error) {
48
+
logger.error(`Error in checkStarterPack for ${did}:`, error);
49
+
throw error;
50
+
}
46
51
};
47
52
48
53
export const checkNewStarterPack = async (
···
53
58
packName: string | undefined,
54
59
description: string | undefined,
55
60
) => {
56
-
const labels: string[] = Array.from(
57
-
STARTERPACK_CHECKS,
58
-
(SPCheck) => SPCheck.label,
59
-
);
60
-
61
-
labels.forEach((label) => {
62
-
const checkList = PROFILE_CHECKS.find((SPCheck) => SPCheck.label === label);
61
+
try {
62
+
const labels: string[] = Array.from(
63
+
STARTERPACK_CHECKS,
64
+
(SPCheck) => SPCheck.label,
65
+
);
63
66
64
-
if (checkList?.knownVectors?.includes(did)) {
65
-
createPostLabel(
66
-
atURI,
67
-
cid,
68
-
`${checkList!.label}`,
69
-
`${time}: Starter pack created by known vector for ${checkList!.label} at: ${atURI}"`,
70
-
);
71
-
createAccountReport(
72
-
did,
73
-
`${time}: Starter pack created by known vector for ${checkList!.label} at: ${atURI}"`,
74
-
);
75
-
}
67
+
labels.forEach((label) => {
68
+
const checkList = PROFILE_CHECKS.find((SPCheck) => SPCheck.label === label);
76
69
77
-
if (description) {
78
-
if (checkList!.check.test(description)) {
79
-
logger.info(`Labeling post: ${atURI}`);
70
+
if (checkList?.knownVectors?.includes(did)) {
80
71
createPostLabel(
81
72
atURI,
82
73
cid,
83
-
`${checkList!.label}`,
84
-
`${time}: ${checkList!.comment} at ${atURI} with text "${description}"`,
74
+
checkList.label,
75
+
`${time}: Starter pack created by known vector for ${checkList.label} at: ${atURI}"`,
85
76
);
86
77
createAccountReport(
87
78
did,
88
-
`${time}: ${checkList!.comment} at ${atURI} with text "${description}"`,
79
+
`${time}: Starter pack created by known vector for ${checkList.label} at: ${atURI}"`,
89
80
);
90
81
}
91
-
}
92
82
93
-
if (packName) {
94
-
if (checkList!.check.test(packName)) {
95
-
logger.info(`Labeling post: ${atURI}`);
96
-
createPostLabel(
97
-
atURI,
98
-
cid,
99
-
`${checkList!.label}`,
100
-
`${time}: ${checkList!.comment} at ${atURI} with pack name "${packName}"`,
101
-
);
102
-
createAccountReport(
103
-
did,
104
-
`${time}: ${checkList!.comment} at ${atURI} with pack name "${packName}"`,
105
-
);
83
+
if (description) {
84
+
if (checkList!.check.test(description)) {
85
+
logger.info(`Labeling post: ${atURI}`);
86
+
createPostLabel(
87
+
atURI,
88
+
cid,
89
+
checkList!.label,
90
+
`${time}: ${checkList!.comment} at ${atURI} with text "${description}"`,
91
+
);
92
+
createAccountReport(
93
+
did,
94
+
`${time}: ${checkList!.comment} at ${atURI} with text "${description}"`,
95
+
);
96
+
}
106
97
}
107
-
}
108
-
});
98
+
99
+
if (packName) {
100
+
if (checkList!.check.test(packName)) {
101
+
logger.info(`Labeling post: ${atURI}`);
102
+
createPostLabel(
103
+
atURI,
104
+
cid,
105
+
checkList!.label,
106
+
`${time}: ${checkList!.comment} at ${atURI} with pack name "${packName}"`,
107
+
);
108
+
createAccountReport(
109
+
did,
110
+
`${time}: ${checkList!.comment} at ${atURI} with pack name "${packName}"`,
111
+
);
112
+
}
113
+
}
114
+
});
115
+
} catch (error) {
116
+
logger.error(`Error in checkNewStarterPack for ${did}:`, error);
117
+
throw error;
118
+
}
109
119
};
+173
-93
src/main.ts
+173
-93
src/main.ts
···
90
90
91
91
jetstream.onCreate(
92
92
'app.bsky.feed.post',
93
-
(event: CommitCreateEvent<'app.bsky.feed.post'>) => {
94
-
const atURI = `at://${event.did}/app.bsky.feed.post/${event.commit.rkey}`;
95
-
const hasFacets = event.commit.record.hasOwnProperty('facets');
96
-
const hasText = event.commit.record.hasOwnProperty('text');
93
+
async (event: CommitCreateEvent<'app.bsky.feed.post'>) => {
94
+
try {
95
+
const atURI = `at://${event.did}/app.bsky.feed.post/${event.commit.rkey}`;
96
+
const hasFacets = event.commit.record.hasOwnProperty('facets');
97
+
const hasText = event.commit.record.hasOwnProperty('text');
97
98
98
-
const tasks: Promise<void>[] = [];
99
-
100
-
// Check if the record has facets
101
-
if (hasFacets) {
102
-
const hasLinkType = event.commit.record.facets!.some((facet) =>
103
-
facet.features.some(
104
-
(feature) => feature.$type === 'app.bsky.richtext.facet#link',
105
-
),
106
-
);
99
+
const tasks: Promise<void>[] = [];
107
100
108
-
if (hasLinkType) {
109
-
const urls = event.commit.record
110
-
.facets!.flatMap((facet) =>
111
-
facet.features.filter(
101
+
// Check if the record has facets
102
+
if (hasFacets && event.commit.record.facets) {
103
+
const hasLinkType = event.commit.record.facets.some((facet) =>
104
+
facet.features.some(
112
105
(feature) => feature.$type === 'app.bsky.richtext.facet#link',
113
106
),
114
-
)
115
-
.map((feature: LinkFeature) => feature.uri);
107
+
);
108
+
109
+
if (hasLinkType) {
110
+
const urls = event.commit.record.facets.flatMap((facet) =>
111
+
facet.features.filter(
112
+
(feature) => feature.$type === 'app.bsky.richtext.facet#link',
113
+
),
114
+
)
115
+
.map((feature: LinkFeature) => feature.uri);
116
+
117
+
urls.forEach((url) => {
118
+
const posts: Post[] = [
119
+
{
120
+
did: event.did,
121
+
time: event.time_us,
122
+
rkey: event.commit.rkey,
123
+
atURI,
124
+
text: url,
125
+
cid: event.commit.cid,
126
+
},
127
+
];
128
+
tasks.push(checkPosts(posts).catch((error) => {
129
+
logger.error(`Error checking post links for ${event.did}:`, error);
130
+
}));
131
+
});
132
+
}
133
+
} else if (hasText && event.commit.record.text) {
134
+
const posts: Post[] = [
135
+
{
136
+
did: event.did,
137
+
time: event.time_us,
138
+
rkey: event.commit.rkey,
139
+
atURI,
140
+
text: event.commit.record.text,
141
+
cid: event.commit.cid,
142
+
},
143
+
];
144
+
tasks.push(checkPosts(posts).catch((error) => {
145
+
logger.error(`Error checking post text for ${event.did}:`, error);
146
+
}));
147
+
}
116
148
117
-
urls.forEach((url) => {
118
-
const posts: Post[] = [
119
-
{
120
-
did: event.did,
121
-
time: event.time_us,
122
-
rkey: event.commit.rkey,
123
-
atURI,
124
-
text: url,
125
-
cid: event.commit.cid,
126
-
},
127
-
];
128
-
tasks.push(checkPosts(posts));
129
-
});
149
+
// Wait for all tasks to complete
150
+
if (tasks.length > 0) {
151
+
await Promise.allSettled(tasks);
130
152
}
131
-
} else if (hasText) {
132
-
const posts: Post[] = [
133
-
{
134
-
did: event.did,
135
-
time: event.time_us,
136
-
rkey: event.commit.rkey,
137
-
atURI,
138
-
text: event.commit.record.text,
139
-
cid: event.commit.cid,
140
-
},
141
-
];
142
-
tasks.push(checkPosts(posts));
153
+
} catch (error) {
154
+
logger.error(`Error processing post event for ${event.did}:`, error);
143
155
}
144
156
},
145
157
);
···
149
161
'app.bsky.actor.profile',
150
162
async (event: CommitUpdateEvent<'app.bsky.actor.profile'>) => {
151
163
try {
164
+
const tasks: Promise<void>[] = [];
165
+
152
166
if (event.commit.record.displayName || event.commit.record.description) {
153
-
checkDescription(
154
-
event.did,
155
-
event.time_us,
156
-
event.commit.record.displayName!,
157
-
event.commit.record.description!,
167
+
const displayName = event.commit.record.displayName ?? '';
168
+
const description = event.commit.record.description ?? '';
169
+
170
+
tasks.push(
171
+
checkDescription(event.did, event.time_us, displayName, description)
172
+
.catch((error) => {
173
+
logger.error(`Error checking profile description for ${event.did}:`, error);
174
+
})
158
175
);
159
-
checkDisplayName(
160
-
event.did,
161
-
event.time_us,
162
-
event.commit.record.displayName!,
163
-
event.commit.record.description!,
176
+
177
+
tasks.push(
178
+
checkDisplayName(event.did, event.time_us, displayName, description)
179
+
.catch((error) => {
180
+
logger.error(`Error checking profile display name for ${event.did}:`, error);
181
+
})
164
182
);
165
183
}
166
184
167
185
if (event.commit.record.joinedViaStarterPack) {
168
-
checkStarterPack(
169
-
event.did,
170
-
event.time_us,
171
-
event.commit.record.joinedViaStarterPack.uri,
186
+
tasks.push(
187
+
checkStarterPack(event.did, event.time_us, event.commit.record.joinedViaStarterPack.uri)
188
+
.catch((error) => {
189
+
logger.error(`Error checking starter pack for ${event.did}:`, error);
190
+
})
172
191
);
173
192
}
193
+
194
+
// Wait for all tasks to complete
195
+
if (tasks.length > 0) {
196
+
await Promise.allSettled(tasks);
197
+
}
174
198
} catch (error) {
175
-
logger.error(`Error checking profile: ${error}`);
199
+
logger.error(`Error processing profile update event for ${event.did}:`, error);
176
200
}
177
201
},
178
202
);
···
183
207
'app.bsky.actor.profile',
184
208
async (event: CommitCreateEvent<'app.bsky.actor.profile'>) => {
185
209
try {
210
+
const tasks: Promise<void>[] = [];
211
+
186
212
if (event.commit.record.displayName || event.commit.record.description) {
187
-
checkDescription(
188
-
event.did,
189
-
event.time_us,
190
-
event.commit.record.displayName!,
191
-
event.commit.record.description!,
213
+
const displayName = event.commit.record.displayName ?? '';
214
+
const description = event.commit.record.description ?? '';
215
+
216
+
tasks.push(
217
+
checkDescription(event.did, event.time_us, displayName, description)
218
+
.catch((error) => {
219
+
logger.error(`Error checking profile description for ${event.did}:`, error);
220
+
})
192
221
);
193
-
checkDisplayName(
194
-
event.did,
195
-
event.time_us,
196
-
event.commit.record.displayName!,
197
-
event.commit.record.description!,
222
+
223
+
tasks.push(
224
+
checkDisplayName(event.did, event.time_us, displayName, description)
225
+
.catch((error) => {
226
+
logger.error(`Error checking profile display name for ${event.did}:`, error);
227
+
})
198
228
);
199
229
200
230
if (event.commit.record.joinedViaStarterPack) {
201
-
checkStarterPack(
202
-
event.did,
203
-
event.time_us,
204
-
event.commit.record.joinedViaStarterPack.uri,
231
+
tasks.push(
232
+
checkStarterPack(event.did, event.time_us, event.commit.record.joinedViaStarterPack.uri)
233
+
.catch((error) => {
234
+
logger.error(`Error checking starter pack for ${event.did}:`, error);
235
+
})
205
236
);
206
237
}
207
-
} else {
208
-
return;
238
+
239
+
// Wait for all tasks to complete
240
+
if (tasks.length > 0) {
241
+
await Promise.allSettled(tasks);
242
+
}
209
243
}
210
244
} catch (error) {
211
-
logger.error(`Error checking profile: ${error}`);
245
+
logger.error(`Error processing profile creation event for ${event.did}:`, error);
212
246
}
213
247
},
214
248
);
···
218
252
async (event: CommitCreateEvent<'app.bsky.graph.starterpack'>) => {
219
253
try {
220
254
const atURI = `at://${event.did}/app.bsky.feed.post/${event.commit.rkey}`;
255
+
const name = event.commit.record.name ?? '';
256
+
const description = event.commit.record.description ?? '';
221
257
222
-
checkNewStarterPack(
258
+
await checkNewStarterPack(
223
259
event.did,
224
260
event.time_us,
225
261
atURI,
226
262
event.commit.cid,
227
-
event.commit.record.name,
228
-
event.commit.record.description,
229
-
);
263
+
name,
264
+
description,
265
+
).catch((error) => {
266
+
logger.error(`Error checking new starter pack for ${event.did}:`, error);
267
+
});
230
268
} catch (error) {
231
-
logger.error(`Error checking starterpack: ${error}`);
269
+
logger.error(`Error processing starter pack creation event for ${event.did}:`, error);
232
270
}
233
271
},
234
272
);
···
238
276
async (event: CommitUpdateEvent<'app.bsky.graph.starterpack'>) => {
239
277
try {
240
278
const atURI = `at://${event.did}/app.bsky.feed.post/${event.commit.rkey}`;
279
+
const name = event.commit.record.name ?? '';
280
+
const description = event.commit.record.description ?? '';
241
281
242
-
checkNewStarterPack(
282
+
await checkNewStarterPack(
243
283
event.did,
244
284
event.time_us,
245
285
atURI,
246
286
event.commit.cid,
247
-
event.commit.record.name,
248
-
event.commit.record.description,
249
-
);
287
+
name,
288
+
description,
289
+
).catch((error) => {
290
+
logger.error(`Error checking updated starter pack for ${event.did}:`, error);
291
+
});
250
292
} catch (error) {
251
-
logger.error(`Error checking starterpack: ${error}`);
293
+
logger.error(`Error processing starter pack update event for ${event.did}:`, error);
252
294
}
253
295
},
254
296
);
255
297
256
298
// Check for handle updates
257
299
jetstream.on('identity', async (event: IdentityEvent) => {
258
-
if (event.identity.handle) {
259
-
checkHandle(event.identity.did, event.identity.handle, event.time_us);
300
+
try {
301
+
if (event.identity.handle) {
302
+
await checkHandle(event.identity.did, event.identity.handle, event.time_us)
303
+
.catch((error) => {
304
+
logger.error(`Error checking handle for ${event.identity.did}:`, error);
305
+
});
306
+
}
307
+
} catch (error) {
308
+
logger.error(`Error processing identity event for ${event.identity.did}:`, error);
260
309
}
261
310
});
262
311
263
-
const metricsServer = startMetricsServer(METRICS_PORT);
312
+
// Start metrics server with error handling
313
+
let metricsServer;
314
+
try {
315
+
metricsServer = startMetricsServer(METRICS_PORT);
316
+
logger.info(`Metrics server started on port ${METRICS_PORT}`);
317
+
} catch (error) {
318
+
logger.error('Failed to start metrics server:', error);
319
+
process.exit(1);
320
+
}
264
321
265
322
/* labelerServer.app.listen({ port: PORT, host: HOST }, (error, address) => {
266
323
if (error) {
···
270
327
}
271
328
});*/
272
329
273
-
jetstream.start();
330
+
// Start jetstream with error handling
331
+
try {
332
+
jetstream.start();
333
+
logger.info('Jetstream started successfully');
334
+
} catch (error) {
335
+
logger.error('Failed to start jetstream:', error);
336
+
process.exit(1);
337
+
}
274
338
275
339
function shutdown() {
276
340
try {
277
341
logger.info('Shutting down gracefully...');
278
-
fs.writeFileSync('cursor.txt', jetstream.cursor!.toString(), 'utf8');
342
+
if (jetstream.cursor) {
343
+
fs.writeFileSync('cursor.txt', jetstream.cursor.toString(), 'utf8');
344
+
}
279
345
jetstream.close();
280
-
metricsServer.close();
346
+
if (metricsServer) {
347
+
metricsServer.close();
348
+
}
349
+
logger.info('Shutdown completed successfully');
281
350
} catch (error) {
282
-
logger.error(`Error shutting down gracefully: ${error}`);
351
+
logger.error('Error shutting down gracefully:', error);
283
352
process.exit(1);
284
353
}
285
354
}
355
+
356
+
// Global error handlers
357
+
process.on('unhandledRejection', (reason, promise) => {
358
+
logger.error('Unhandled Promise Rejection at:', promise, 'reason:', reason);
359
+
// Don't exit the process for unhandled rejections, just log them
360
+
});
361
+
362
+
process.on('uncaughtException', (error) => {
363
+
logger.error('Uncaught Exception:', error);
364
+
shutdown();
365
+
});
286
366
287
367
process.on('SIGINT', shutdown);
288
368
process.on('SIGTERM', shutdown);
+18
-12
src/moderation.ts
+18
-12
src/moderation.ts
···
40
40
},
41
41
},
42
42
);
43
-
} catch (e) {
44
-
console.error(e);
43
+
} catch (error) {
44
+
logger.error(`Error creating post label for URI ${uri}:`, error);
45
+
throw error;
45
46
}
46
47
});
47
48
};
···
80
81
},
81
82
},
82
83
);
83
-
} catch (e) {
84
-
console.error(e);
84
+
} catch (error) {
85
+
logger.error(`Error creating account label for DID ${did}:`, error);
86
+
throw error;
85
87
}
86
88
});
87
89
};
···
120
122
},
121
123
},
122
124
);
123
-
} catch (e) {
124
-
console.error(e);
125
+
} catch (error) {
126
+
logger.error(`Error creating post report for URI ${uri}:`, error);
127
+
throw error;
125
128
}
126
129
});
127
130
};
···
154
157
},
155
158
},
156
159
);
157
-
} catch (e) {
158
-
console.error(e);
160
+
} catch (error) {
161
+
logger.error(`Error creating account comment for DID ${did}:`, error);
162
+
throw error;
159
163
}
160
164
});
161
165
};
···
189
193
},
190
194
},
191
195
);
192
-
} catch (e) {
193
-
console.error(e);
196
+
} catch (error) {
197
+
logger.error(`Error creating account report for DID ${did}:`, error);
198
+
throw error;
194
199
}
195
200
});
196
201
};
···
220
225
createdAt: new Date().toISOString(),
221
226
},
222
227
});
223
-
} catch (e) {
224
-
console.error(e);
228
+
} catch (error) {
229
+
logger.error(`Error adding DID ${did} to list ${label}:`, error);
230
+
throw error;
225
231
}
226
232
});
227
233
};
+16
-16
src/monitor.ts
+16
-16
src/monitor.ts
···
31
31
32
32
if (description) {
33
33
if (checkProfiles?.description === true) {
34
-
if (checkProfiles!.check.test(description)) {
35
-
if (checkProfiles!.whitelist) {
36
-
if (checkProfiles!.whitelist.test(description)) {
34
+
if (checkProfiles.check.test(description)) {
35
+
if (checkProfiles.whitelist) {
36
+
if (checkProfiles.whitelist.test(description)) {
37
37
logger.info('Whitelisted phrase found.');
38
38
return;
39
39
}
40
40
} else {
41
-
logger.info(`${checkProfiles!.label} in description for ${did}`);
41
+
logger.info(`${checkProfiles.label} in description for ${did}`);
42
42
}
43
43
44
-
if (checkProfiles!.reportOnly === true) {
44
+
if (checkProfiles.reportOnly === true) {
45
45
createAccountReport(
46
46
did,
47
-
`${time}: ${checkProfiles!.comment} - ${displayName} - ${description}`,
47
+
`${time}: ${checkProfiles.comment} - ${displayName} - ${description}`,
48
48
);
49
49
return;
50
50
} else {
51
51
createAccountLabel(
52
52
did,
53
-
`${checkProfiles!.label}`,
54
-
`${time}: ${checkProfiles!.comment}`,
53
+
checkProfiles.label,
54
+
`${time}: ${checkProfiles.comment}`,
55
55
);
56
56
}
57
57
}
···
87
87
88
88
if (displayName) {
89
89
if (checkProfiles?.displayName === true) {
90
-
if (checkProfiles!.check.test(displayName)) {
91
-
if (checkProfiles!.whitelist) {
92
-
if (checkProfiles!.whitelist.test(displayName)) {
90
+
if (checkProfiles.check.test(displayName)) {
91
+
if (checkProfiles.whitelist) {
92
+
if (checkProfiles.whitelist.test(displayName)) {
93
93
logger.info('Whitelisted phrase found.');
94
94
return;
95
95
}
96
96
} else {
97
-
logger.info(`${checkProfiles!.label} in displayName for ${did}`);
97
+
logger.info(`${checkProfiles.label} in displayName for ${did}`);
98
98
}
99
99
100
-
if (checkProfiles!.reportOnly === true) {
100
+
if (checkProfiles.reportOnly === true) {
101
101
createAccountReport(
102
102
did,
103
-
`${time}: ${checkProfiles!.comment} - ${displayName} - ${description}`,
103
+
`${time}: ${checkProfiles.comment} - ${displayName} - ${description}`,
104
104
);
105
105
return;
106
106
} else {
107
107
createAccountLabel(
108
108
did,
109
-
`${checkProfiles!.label}`,
110
-
`${time}: ${checkProfiles!.comment}`,
109
+
checkProfiles.label,
110
+
`${time}: ${checkProfiles.comment}`,
111
111
);
112
112
}
113
113
}
+13
-8
src/utils.ts
+13
-8
src/utils.ts
···
73
73
return 'eng';
74
74
}
75
75
76
-
const lande = (await import('lande')).default;
77
-
const langsProbabilityMap = lande(profileText);
76
+
try {
77
+
const lande = (await import('lande')).default;
78
+
const langsProbabilityMap = lande(profileText);
78
79
79
-
// Sort by probability in descending order
80
-
langsProbabilityMap.sort(
81
-
(a: [string, number], b: [string, number]) => b[1] - a[1],
82
-
);
80
+
// Sort by probability in descending order
81
+
langsProbabilityMap.sort(
82
+
(a: [string, number], b: [string, number]) => b[1] - a[1],
83
+
);
83
84
84
-
// Return the language code with the highest probability
85
-
return langsProbabilityMap[0][0];
85
+
// Return the language code with the highest probability
86
+
return langsProbabilityMap[0][0];
87
+
} catch (error) {
88
+
logger.error('Error detecting language, defaulting to \'eng\':', error);
89
+
return 'eng'; // Fallback to English on error
90
+
}
86
91
}