Skip to content

Commit

Permalink
Merge pull request #12 from nacika-ins/feat/reporting-only-mode
Browse files Browse the repository at this point in the history
Reporting only mode
  • Loading branch information
nacika-ins authored Feb 23, 2024
2 parents b70ac8b + 9a4d763 commit 4a23605
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 124 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@
"react/jsx-one-expression-per-line": 0,
"padded-blocks": 0,
"import/no-extraneous-dependencies": 0,
"no-unused-vars": [1, { "varsIgnorePattern": "_" }]
"no-unused-vars": [1, { "varsIgnorePattern": "_" }],
"no-continue": 0
},
"settings": {
"import/resolver": {
Expand Down
36 changes: 36 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Release
on:
push:
branches:
- master

permissions:
contents: read

jobs:
release:
name: Release
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "lts/*"
- name: Install dependencies
run: npm clean-install
- name: Verify the integrity of provenance attestations and registry signatures for installed dependencies
run: npm audit signatures
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
42 changes: 14 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,22 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
# Fediverse security manager

## Getting Started
This is a simple security manager for the Fediverse.

First, run the development server:
This software automatically reports spam in the global timeline by detecting text matches and image MD5 hash values. It is also possible to automatically suspend spam accounts to the hostile after reporting.

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
## How can I learn more?

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
Release notes are available via Patron.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
* [日本語](https://www.patreon.com/posts/mastodon-nozi-98674490)
* [English](https://www.patreon.com/posts/created-spam-for-98757566)

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Road map

## Learn More
- [x] Automatic spam reporting
- [x] Automatic account suspension
- [x] Automatic spam detection
- [ ] Automatic Tor IP address blocking
- [ ] Automatic spammer IP address blocking
- [ ] Preventing registration by instant email address

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
1 change: 1 addition & 0 deletions app/automatic-spam-reporting/formSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ export const formSchema = z.object({
apiEndpoint: z.string().url().min(1),
apiToken: z.string().min(1),
adminApiToken: z.string().min(1),
isReportOnly: z.boolean().default(false),
})),
});
119 changes: 27 additions & 92 deletions components/organisms/SettingContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,32 @@ export const SettingContainer: FC<{ update: typeof update; get: typeof get } & P
/>
</div>

<div>
<FormField
control={form.control}
name={`targetProviders.${index}.isReportOnly`}
render={({ field }) => (
<FormItem>
<FormLabel>
Reporting only mode
</FormLabel>
<FormDescription>
Only reporting is performed. Administrative privileges are not required.
</FormDescription>
<FormControl>
<div className="relative">
<div className="flex items-center gap-2 text-sm">
<Switch onCheckedChange={field.onChange} checked={field.value} />
Enable
</div>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>

</CardContent>
<div className="absolute right-1 top-1">
<Button variant="ghost" size="icon" onClick={() => remove(index)}>
Expand All @@ -295,105 +321,14 @@ export const SettingContainer: FC<{ update: typeof update; get: typeof get } & P
name: '',
providerType: 'mastodon',
adminApiToken: '',
isReportOnly: false,
})}
>
Add provider
</Button>
</div>

</div>

{/* <FormField */}
{/* control={form.control} */}
{/* name="email" */}
{/* render={({ field }) => ( */}
{/* <FormItem> */}
{/* <FormLabel>Email</FormLabel> */}
{/* <Select */}
{/* onValueChange={field.onChange} */}
{/* defaultValue={field.value} */}
{/* > */}
{/* <FormControl> */}
{/* <SelectTrigger> */}
{/* <SelectValue placeholder="Select a verified email to display" /> */}
{/* </SelectTrigger> */}
{/* </FormControl> */}
{/* <SelectContent> */}
{/* <SelectItem value="[email protected]"> */}
{/* [email protected] */}
{/* </SelectItem> */}
{/* <SelectItem value="[email protected]"> */}
{/* [email protected] */}
{/* </SelectItem> */}
{/* <SelectItem value="[email protected]"> */}
{/* [email protected] */}
{/* </SelectItem> */}
{/* </SelectContent> */}
{/* </Select> */}
{/* <FormDescription> */}
{/* You can manage verified email addresses in your{' '} */}
{/* <Link href="/examples/forms">email settings</Link>. */}
{/* </FormDescription> */}
{/* <FormMessage /> */}
{/* </FormItem> */}
{/* )} */}
{/* /> */}
{/* <FormField */}
{/* control={form.control} */}
{/* name="bio" */}
{/* render={({ field }) => ( */}
{/* <FormItem> */}
{/* <FormLabel>Bio</FormLabel> */}
{/* <FormControl> */}
{/* <Textarea */}
{/* placeholder="Tell us a little bit about yourself" */}
{/* className="resize-none" */}
{/* {...field} */}
{/* /> */}
{/* </FormControl> */}
{/* <FormDescription> */}
{/* You can <span>@mention</span> other users and */}
{/* organizations to link to them. */}
{/* </FormDescription> */}
{/* <FormMessage /> */}
{/* </FormItem> */}
{/* )} */}
{/* /> */}
{/* <div> */}
{/* {fields.map((field, index) => ( */}
{/* <FormField */}
{/* control={form.control} */}
{/* key={field.id} */}
{/* name={`urls.${index}.value`} */}
{/* render={({ field }) => ( */}
{/* <FormItem> */}
{/* <FormLabel className={cn(index !== 0 && 'sr-only')}> */}
{/* URLs */}
{/* </FormLabel> */}
{/* <FormDescription */}
{/* className={cn(index !== 0 && 'sr-only')} */}
{/* > */}
{/* Add links to your website, blog, or social media */}
{/* profiles. */}
{/* </FormDescription> */}
{/* <FormControl> */}
{/* <Input {...field} /> */}
{/* </FormControl> */}
{/* <FormMessage /> */}
{/* </FormItem> */}
{/* )} */}
{/* /> */}
{/* ))} */}
{/* <Button */}
{/* type="button" */}
{/* variant="outline" */}
{/* size="sm" */}
{/* className="mt-2" */}
{/* onClick={() => append({ value: '' })} */}
{/* > */}
{/* Add URL */}
{/* </Button> */}
{/* </div> */}
<Button type="submit">Update</Button>
</form>
</Form>
Expand Down
7 changes: 4 additions & 3 deletions features/batch/mastodon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ export const execMastodon = async (provider: TargetProvider, spamTexts: string[]
imageMD5s.includes(spamText),
);
console.debug('found =', found);
// eslint-disable-next-line no-continue
if (!found) continue;

// report target
Expand All @@ -100,6 +99,7 @@ export const execMastodon = async (provider: TargetProvider, spamTexts: string[]
console.debug('status?.id =', status?.id);

// Report spam
console.debug('[Report spam] status.account?.id =', status.account?.id, 'statusId =', status?.id);
const report = await retry(async () => masto.v1.reports.create({
accountId: status.account?.id,
statusIds: [status?.id]?.filter((value): value is string => !!value),
Expand All @@ -109,6 +109,8 @@ export const execMastodon = async (provider: TargetProvider, spamTexts: string[]
}));
console.debug('report =', report);

if (provider.isReportOnly) continue;

// Suspend User
console.debug('[Suspend User] report.targetAccount.id =', report.targetAccount.id);
const suspendResult = await retry(async () => adminMasto.v1.admin.accounts.$select(report.targetAccount.id).action.create({
Expand All @@ -124,8 +126,7 @@ export const execMastodon = async (provider: TargetProvider, spamTexts: string[]
const resolveResult = await retry(async () => adminMasto.v1.admin.reports.$select(report.id).resolve());
console.debug('resolveResult =', resolveResult);

} catch
(e) {
} catch (e) {
console.error('error =', e);
}
}
Expand Down
2 changes: 2 additions & 0 deletions features/batch/misskey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ export const execMisskey = async (provider: TargetProvider, spamTexts: string[],
throw new Error('Target User ID is not found');
}

if (provider.isReportOnly) continue;

// Delete note ( When 200OK, no value is returned )
console.debug('[deleteNote] note?.id =', note?.id);
await retry(() => deleteNote({ provider, noteId: note?.id }));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_TargetProvider" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL,
"enabled" BOOLEAN NOT NULL DEFAULT false,
"providerType" TEXT NOT NULL,
"apiEndpoint" TEXT NOT NULL,
"apiToken" TEXT NOT NULL,
"adminApiToken" TEXT NOT NULL,
"isReportOnly" BOOLEAN NOT NULL DEFAULT false,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_TargetProvider" ("adminApiToken", "apiEndpoint", "apiToken", "createdAt", "enabled", "id", "name", "providerType", "updatedAt") SELECT "adminApiToken", "apiEndpoint", "apiToken", "createdAt", "enabled", "id", "name", "providerType", "updatedAt" FROM "TargetProvider";
DROP TABLE "TargetProvider";
ALTER TABLE "new_TargetProvider" RENAME TO "TargetProvider";
PRAGMA foreign_key_check;
PRAGMA foreign_keys=ON;
1 change: 1 addition & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ model TargetProvider {
apiEndpoint String
apiToken String
adminApiToken String
isReportOnly Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Expand Down

0 comments on commit 4a23605

Please sign in to comment.