Compare commits

9 Commits
dev ... master

Author SHA1 Message Date
Benjamin Kyd
124c36cca8 Update README.md 2021-03-10 23:31:37 +00:00
Ben
9b4140ba86 bruh 2020-08-28 21:52:21 +01:00
Ben
4594be6f94 hotfix - bug in the bloody message edit event 2020-08-10 19:31:37 +01:00
Ben
7fa3f8406d changed formatting 2020-08-10 17:48:06 +01:00
Ben
72cdb48235 Merge branch 'master' of https://github.com/benkyd/logori 2020-08-10 13:14:43 +01:00
Ben
d1b2a34f54 bruh 2020-08-10 13:14:29 +01:00
Benjamin Kyd
94886f23c0 Merge pull request #6 from aosync/harmful
Did some things here and there.
2020-08-07 16:25:46 +01:00
Alejandro Sior
2468b6e697 Cleaned some things in the message delete event 2020-08-07 15:20:06 +00:00
Alejandro Sior
5056ff65e6 Added audit log fetch wrapper to check if recent enough. (and other things) 2020-08-07 15:09:32 +00:00
7 changed files with 220 additions and 176 deletions

View File

@@ -1,36 +1,36 @@
# Privacy Policy for Logori # Privacy Policy for Logori
At Logori, accessible from https://logori.xyz, one of our main priorities is the privacy of our visitors. This Privacy Policy document contains types of information that is collected and recorded by Logori and how we use it. At Logori, accessible from https://logori.xyz, one of our main priorities is the privacy of our visitors. This Privacy Policy document contains types of information that is collected and recorded by Logori and how we use it.
If you have additional questions or require more information about our Privacy Policy, do not hesitate to contact us at benjaminkyd@gmail.com. If you have additional questions or require more information about our Privacy Policy, do not hesitate to contact us at benjaminkyd@gmail.com.
It is the responsibility of the guild owner to make the members aware of Logoris presence as a background application. It is the responsibility of the guild owner to make the members aware of Logoris presence as a background application.
## Log Files ## Log Files
Logori follows a standard procedure of using log files. These files log visitors when they visit websites. All hosting companies do this and a part of hosting services' analytics. The information collected by log files include internet protocol (IP) addresses, browser type, Internet Service Provider (ISP), date and time stamp, referring/exit pages, and possibly the number of clicks. These are not linked to any information that is personally identifiable. The purpose of the information is for analyzing trends, administering the site, tracking users' movement on the website, and gathering demographic information. Logori follows a standard procedure of using log files. These files log visitors when they visit websites. All hosting companies do this and a part of hosting services' analytics. The information collected by log files include internet protocol (IP) addresses, browser type, Internet Service Provider (ISP), date and time stamp, referring/exit pages, and possibly the number of clicks. These are not linked to any information that is personally identifiable. The purpose of the information is for analyzing trends, administering the site, tracking users' movement on the website, and gathering demographic information.
## The Logori Application ## The Logori Application
Logori is primarily a logging application which means it takes and stores data provided to it by the Discord API which is a third-party service. Logori does not control the data that discord provides it and logs it for the administrative purpose of the Discord Guild. Logori is primarily a logging application which means it takes and stores data provided to it by the Discord API which is a third-party service. Logori does not control the data that discord provides it and logs it for the administrative purpose of the Discord Guild.
## Privacy Policies ## Privacy Policies
You may consult this list to find the Privacy Policy for each of the advertising partners of Logori. Our Privacy Policy was created with the help of the Free Privacy Policy Generator and the Privacy Policy Generator Online. You may consult this list to find the Privacy Policy for each of the advertising partners of Logori. Our Privacy Policy was created with the help of the Free Privacy Policy Generator and the Privacy Policy Generator Online.
Note that Logori has no access to or control over these cookies that are used by third-party providors. Note that Logori has no access to or control over these cookies that are used by third-party providors.
## Third Party Privacy Policies ## Third Party Privacy Policies
Logori's Privacy Policy does not apply to other advertisers or websites. Thus, we are advising you to consult the respective Privacy Policies of these third-party services (including Discord) for more detailed information. It may include their practices and instructions about how to opt-out of certain options. Logori's Privacy Policy does not apply to other advertisers or websites. Thus, we are advising you to consult the respective Privacy Policies of these third-party services (including Discord) for more detailed information. It may include their practices and instructions about how to opt-out of certain options.
## Children's Information ## Children's Information
Another part of our priority is adding protection for children while using the internet. We encourage parents and guardians to observe, participate in, and/or monitor and guide their online activity. Another part of our priority is adding protection for children while using the internet. We encourage parents and guardians to observe, participate in, and/or monitor and guide their online activity.
Logori does not knowingly collect any Personal Identifiable Information from children under the age of 13. If you think that your child provided this kind of information on our website, we strongly encourage you to contact us immediately and we will do our best efforts to promptly remove such information from our records. Logori does not knowingly collect any Personal Identifiable Information from children under the age of 13. If you think that your child provided this kind of information on our website, we strongly encourage you to contact us immediately and we will do our best efforts to promptly remove such information from our records.
## Your Data ## Your Data
Your data is secured with state-of-the-art military-grade encryption as your privacy is our #1 concern when it comes to a data heavy application such as logori. Your data is secured with state-of-the-art military-grade encryption as your privacy is our #1 concern when it comes to a data heavy application such as logori.
In compliance with GDPR, your data is available to view at any time on the website and a full data dump can be requested at benjaminkyd@gmail.com a full user data purge can also be requested. In compliance with GDPR, your data is available to view at any time on the website and a full data dump can be requested at benjaminkyd@gmail.com a full user data purge can also be requested.
## Online Privacy Policy Only ## Online Privacy Policy Only
This Privacy Policy applies only to our online activities and is valid for visitors to our website with regards to the information that they shared and/or collect in Logori. This policy is not applicable to any information collected offline or via channels other than this website. This Privacy Policy applies only to our online activities and is valid for visitors to our website with regards to the information that they shared and/or collect in Logori. This policy is not applicable to any information collected offline or via channels other than this website.
## Consent ## Consent
By using Logori, you hereby consent to our Privacy Policy. By using Logori, you hereby consent to our Privacy Policy.

View File

@@ -1,5 +1,7 @@
# logori # logori
[Logori's Website](https://logori.xyz)
## Installation ## Installation
Clone the repo, run `npm install`, run the `index.js` once, then fill the config.json, then rerun the bot. Clone the repo, run `npm install`, run the `index.js` once, then fill the config.json, then rerun the bot.

View File

@@ -1,78 +1,78 @@
module.exports.BlackList = [ module.exports.BlackList = [
"anal", "anal",
"anus", "anus",
"arse", "arse",
"ass", "ass",
"ballsack", "ballsack",
"balls", "balls",
"bastard", "bastard",
"bitch", "bitch",
"biatch", "biatch",
"bloody", "bloody",
"blowjob", "blowjob",
"blow job", "blow job",
"bollock", "bollock",
"bollok", "bollok",
"boner", "boner",
"boob", "boob",
"bugger", "bugger",
"bum", "bum",
"butt", "butt",
"buttplug", "buttplug",
"clitoris", "clitoris",
"cock", "cock",
"coon", "coon",
"crap", "crap",
"cunt", "cunt",
"damn", "damn",
"dick", "dick",
"dildo", "dildo",
"dyke", "dyke",
"fag", "fag",
"feck", "feck",
"fellate", "fellate",
"fellatio", "fellatio",
"felching", "felching",
"fuck", "fuck",
"f u c k", "f u c k",
"fudgepacker", "fudgepacker",
"fudge packer", "fudge packer",
"flange", "flange",
"goddamn", "goddamn",
"god damn", "god damn",
"hell", "hell",
"homo", "homo",
"jerk", "jerk",
"jizz", "jizz",
"knobend", "knobend",
"knob end", "knob end",
"labia", "labia",
"muff", "muff",
"nigger", "nigger",
"nigga", "nigga",
"omg", "omg",
"penis", "penis",
"piss", "piss",
"poop", "poop",
"prick", "prick",
"pube", "pube",
"pussy", "pussy",
"queer", "queer",
"scrotum", "scrotum",
"sex", "sex",
"shit", "shit",
"s hit", "s hit",
"sh1t", "sh1t",
"slut", "slut",
"smegma", "smegma",
"spunk", "spunk",
"tit", "tit",
"tosser", "tosser",
"turd", "turd",
"twat", "twat",
"vagina", "vagina",
"wank", "wank",
"whore", "whore",
"wtf", "wtf",
] ]

View File

@@ -218,16 +218,15 @@ async function ChannelCreate(channel)
let embed = new DiscordEmbed({ let embed = new DiscordEmbed({
title: `${Type} Channel Created`, title: `${Type} Channel Created`,
fields: [
{ name: 'Name', value: channel.mention, inline: true },
{ name: 'Parent Catagory', value: DiscordHelpers.GetGuildCatatory(channel.guild, channel.parentID).name, inline: true }
],
colour: ColourConvert('#42A832'), colour: ColourConvert('#42A832'),
url: 'https://logori.xyz', url: 'https://logori.xyz',
timestamp: new Date(), timestamp: new Date(),
footer: { text: `ID: ${channel.id}` } footer: { text: `ID: ${channel.id}` }
}); });
embed.field('', `**Name:** ${channel.name}\n` +
`**Parent Catagory:** ${DiscordHelpers.GetGuildCatatory(channel.guild, channel.parentID).name}`)
DiscordHelpers.SendMessageSafe(FallbackChannel, {embed: embed.sendable}); DiscordHelpers.SendMessageSafe(FallbackChannel, {embed: embed.sendable});
} }
@@ -242,16 +241,15 @@ async function ChannelDelete(channel)
let embed = new DiscordEmbed({ let embed = new DiscordEmbed({
title: `${Type} Channel Deleted`, title: `${Type} Channel Deleted`,
fields: [
{ name: 'Name', value: channel.name, inline: true },
{ name: 'Parent Catagory', value: DiscordHelpers.GetGuildCatatory(channel.guild, channel.parentID).name, inline: true }
],
colour: ColourConvert('#E0532B'), colour: ColourConvert('#E0532B'),
url: 'https://logori.xyz', url: 'https://logori.xyz',
timestamp: new Date(), timestamp: new Date(),
footer: { text: `ID: ${channel.id}` } footer: { text: `ID: ${channel.id}` }
}); });
embed.field('', `**Name:** ${channel.name}\n` +
`**Parent Catagory:** ${DiscordHelpers.GetGuildCatatory(channel.guild, channel.parentID).name}`)
DiscordHelpers.SendMessageSafe(FallbackChannel, {embed: embed.sendable}); DiscordHelpers.SendMessageSafe(FallbackChannel, {embed: embed.sendable});
} }
@@ -269,31 +267,29 @@ async function ChannelPinUpdate(channel, timestamp, oldtimestamp)
{ {
let embed = new DiscordEmbed({ let embed = new DiscordEmbed({
title: `Pin Created`, title: `Pin Created`,
fields: [
{ name: 'Channel', value: channel.mention, inline: true },
{ name: 'Author', value: LatestPin.author.mention, inline: true },
{ name: 'Content', value: LatestPin.content ? LatestPin.content : "Blank Message", inline: false }
],
colour: ColourConvert('#42A832'), colour: ColourConvert('#42A832'),
url: 'https://logori.xyz', url: 'https://logori.xyz',
timestamp: new Date(timestamp), timestamp: new Date(timestamp),
footer: { text: `ID: ${LatestPin.id}` } footer: { text: `ID: ${LatestPin.id}` }
}); });
embed.field('', `**Channel:** ${channel.mention}\n` +
`**Author:** ${LatestPin.author.mention}\n` +
`**Content:** ${LatesPin.content}`);
DiscordHelpers.SendMessageSafe(FallbackChannel, {embed: embed.sendable}); DiscordHelpers.SendMessageSafe(FallbackChannel, {embed: embed.sendable});
} else } else
{ {
let embed = new DiscordEmbed({ let embed = new DiscordEmbed({
title: `Pin Removed`, title: `Pin Removed`,
fields: [
{ name: 'Channel', value: channel.mention, inline: true },
],
colour: ColourConvert('#E0532B'), colour: ColourConvert('#E0532B'),
url: 'https://logori.xyz', url: 'https://logori.xyz',
timestamp: new Date(timestamp), timestamp: new Date(timestamp),
footer: { text: `ID: ${LatestPin.id}` } footer: { text: `ID: ${LatestPin.id}` }
}); });
embed.field('', `**Channel:** ${channel.mention}`);
DiscordHelpers.SendMessageSafe(FallbackChannel, {embed: embed.sendable}); DiscordHelpers.SendMessageSafe(FallbackChannel, {embed: embed.sendable});
} }
} }
@@ -324,6 +320,10 @@ async function ChannelUpdate(channel, oldchannel)
footer: { text: `ID: ${channel.id}` } footer: { text: `ID: ${channel.id}` }
}); });
// TODO: make these more efficient embeds
// i literally cba to do it rn, aho if you read
// this can you do it please lol
// these include zws characters // these include zws characters
embed.field('', '**Before**', true); embed.field('', '**Before**', true);
embed.field('', '**After**', true); embed.field('', '**After**', true);
@@ -387,6 +387,9 @@ async function ChannelUpdate(channel, oldchannel)
footer: { text: `ID: ${channel.id}` } footer: { text: `ID: ${channel.id}` }
}); });
embed.field('', `**Channel:** ${channel.mention}\n` +
`**Role Overwrite:** ${Role.name}`);
DiscordHelpers.SendMessageSafe(FallbackChannel, {embed: embed.sendable}); DiscordHelpers.SendMessageSafe(FallbackChannel, {embed: embed.sendable});
return; return;
} }
@@ -400,20 +403,20 @@ async function ChannelUpdate(channel, oldchannel)
let embed = new DiscordEmbed({ let embed = new DiscordEmbed({
title: 'Channel Overwrite Removed', title: 'Channel Overwrite Removed',
fields: [
{ name: 'Channel', value: channel.mention, inline: true },
{ name: 'Role Overwrite', value: Role.name, inline: true },
],
colour: ColourConvert('#E0532B'), colour: ColourConvert('#E0532B'),
url: 'https://logori.xyz', url: 'https://logori.xyz',
timestamp: new Date(), timestamp: new Date(),
footer: { text: `ID: ${channel.id}` } footer: { text: `ID: ${channel.id}` }
}); });
embed.field('', `**Channel:** ${channel.mention}\n` +
`**Role Overwrite:** ${Role.name}`);
DiscordHelpers.SendMessageSafe(FallbackChannel, {embed: embed.sendable}); DiscordHelpers.SendMessageSafe(FallbackChannel, {embed: embed.sendable});
return; return;
} }
// TODO: DO THIS !!
// find the overwrites that have changed, there is no chance of a new overwrite // find the overwrites that have changed, there is no chance of a new overwrite
// or a deleted one, a diff must be constructed // or a deleted one, a diff must be constructed
// TODO : make an ambigous role overwrite diff // TODO : make an ambigous role overwrite diff
@@ -458,9 +461,9 @@ async function GuildBanAdd(guild, user)
footer: { text: `ID: ${user.id}` } footer: { text: `ID: ${user.id}` }
}); });
embed.field('', `**Name**: ${user.mention} embed.field('', `**Name**: ${user.mention}\n` +
**Responsible Moderator**: ${Banner.mention} `**Responsible Moderator**: ${Banner.mention}\n` +
**Reason**: ${BanReason}`, false); `**Reason**: ${BanReason}\n`, false);
DiscordHelpers.SendMessageSafe(FallbackChannel, { embed: embed.sendable }); DiscordHelpers.SendMessageSafe(FallbackChannel, { embed: embed.sendable });
} }
@@ -492,8 +495,8 @@ async function GuildBanRemove(guild, user)
footer: { text: `ID: ${user.id}` } footer: { text: `ID: ${user.id}` }
}); });
embed.field('', `**Name**: ${user.mention} embed.field('', `**Name**: ${user.mention}\n` +
**Responsible Moderator**: ${Banner.mention}`, false); `**Responsible Moderator**: ${Banner.mention}`, false);
DiscordHelpers.SendMessageSafe(FallbackChannel, { embed: embed.sendable }); DiscordHelpers.SendMessageSafe(FallbackChannel, { embed: embed.sendable });
} }
@@ -573,14 +576,11 @@ async function GuildMemberAdd(guild, member)
{ } { }
} }
embed.field('', `**Member:** ${member.mention} embed.field('', `**Member:** ${member.mention}\n` +
**AJDS Results:** `**AJDS Results:**\n` +
*${AJDSScore.literalscore}* `*${AJDSScore.literalscore}*\n` +
${WarningString ? WarningString : ''}\n `${WarningString ? WarningString : ''}\n` +
${HarmfulStr ? HarmfulStr : ''}`); `${HarmfulStr ? HarmfulStr : ''}`);
// embed.field('', `${member.mention} is ${AddOrdinalSuffix(DiscordHelpers.GetMemberJoinPos(member.id, guild))} to join`);
DiscordHelpers.SendMessageSafe(FallbackChannel, { embed: embed.sendable }); DiscordHelpers.SendMessageSafe(FallbackChannel, { embed: embed.sendable });
} }
@@ -619,11 +619,8 @@ async function MessageDelete(message)
if (FallbackChannel == -1) return; if (FallbackChannel == -1) return;
// FIXME: Check if audit log entry is recent enough. Because it might cause it to use an entry for a previous action. const LastAuditEntry = await DiscordHelpers.GetRecentEnoughAuditLogEntry(message.channel.guild.id, null, MESSAGE_DELETE);
// When this is implemented, we'll just have to assume deleter is author when no recent enough entry is found. const DeletedMessage = LastAuditEntry ? LastAuditEntry.channel.messages.random() : null;
const LastAuditEntry = (await message.channel.guild.getAuditLogs(1, undefined, MESSAGE_DELETE)).entries[0];
const DeletedMessage = LastAuditEntry.channel.messages.random();
try { try {
let authorMention = 'Author not found'; let authorMention = 'Author not found';
@@ -636,13 +633,8 @@ async function MessageDelete(message)
author.name = message.author.username; author.name = message.author.username;
author.icon_url = message.author.avatarURL; author.icon_url = message.author.avatarURL;
authorMention = message.author.mention; authorMention = message.author.mention;
} else if (DeletedMessage && DeletedMessage.author && DeletedMessage.author.username) {
/* author.name = DeletedMessage.author.username;
author.icon_url = DeletedMessage.author.avatarURL;
authorMention = DeletedMessage.author.mention;
*/
// Left blank because currently inaccurate. When the IMPORTANT comment is achieved, the above lines can be uncommented.
} }
// What gets filled in the channel object of the audit log entry actually comes from the cache, it seems, so we can't know at all :(.
let embed = new DiscordEmbed({ let embed = new DiscordEmbed({
author: author, author: author,
@@ -653,10 +645,10 @@ async function MessageDelete(message)
footer: { text: `ID: ${message.id}` } footer: { text: `ID: ${message.id}` }
}); });
embed.field('', `**Message Owner:** ${authorMention} embed.field('', `**Message Owner:** ${authorMention}\n` +
**Responsible Moderator**: ${responsible} `**Responsible Moderator**: ${responsible}\n` +
**Channel:** ${message.channel.mention} `**Channel:** ${message.channel.mention}\n`
**Message Content:** ${message.content || 'Message was not cached.'} `); `**Message Content:** ${message.content || 'Message was not cached.'} `);
DiscordHelpers.SendMessageSafe(FallbackChannel, { embed: embed.sendable }); DiscordHelpers.SendMessageSafe(FallbackChannel, { embed: embed.sendable });
} catch (e) } catch (e)
@@ -687,11 +679,9 @@ async function MessageUpdate(message, oldmessage)
footer: { text: `ID: ${message.id}` } footer: { text: `ID: ${message.id}` }
}); });
embed.field('', `**Message Owner:** ${message.author.mention} embed.field('', `**Message Owner:** ${message.author.mention}\n` +
**Old Message:**: ${oldmessage.content} `**Old Message:** ${oldmessage.content}\n` +
**New Message:**: ${message.content}`); `**New Message:** ${message.content}`);
DiscordHelpers.SendMessageSafe(FallbackChannel, { embed: embed.sendable }); DiscordHelpers.SendMessageSafe(FallbackChannel, { embed: embed.sendable });
} }

View File

@@ -1,6 +1,29 @@
const Discord = require('./discord.js'); const Discord = require('./discord.js');
const Logger = require('./logger.js'); const Logger = require('./logger.js');
/*
* Following Snowflake class has been taken from aosync's mo discord library.
*/
const DEPOCH = 1420070400000n;
class Snowflake {
constructor(sf) {
this.int = BigInt(sf);
}
getTime() {
return Number((this.int >> 22n) + DEPOCH);
}
getInternalWorkerId() {
return Number((this.int & 0x3E0000n) >> 17n);
}
getInternalProcessId() {
return Number((this.int & 0x1F000n) >> 12n);
}
getIncrement() {
return Number((this.int & 0xFFFn));
}
}
module.exports.IsMemberAdmin = (member) => member.permission.has('administrator') || member.id == process.env.BOT_OWNER; module.exports.IsMemberAdmin = (member) => member.permission.has('administrator') || member.id == process.env.BOT_OWNER;
module.exports.GetGuildCatatory = (guild, catid) => guild.channels.find(c => c.id == catid); module.exports.GetGuildCatatory = (guild, catid) => guild.channels.find(c => c.id == catid);
module.exports.GetGuildRole = (guild, roleid) => guild.roles.find(c => c.id == roleid); module.exports.GetGuildRole = (guild, roleid) => guild.roles.find(c => c.id == roleid);
@@ -25,3 +48,14 @@ module.exports.SendMessageSafe = async (channelid, message) =>
Logger.warn(`Unable to send message in channel ${channelid}`); Logger.warn(`Unable to send message in channel ${channelid}`);
} }
} }
module.exports.GetRecentEnoughAuditLogEntry = async (guildid, before, mask, maxAgeMs) => {
if (!maxAgeMs) maxAgeMs = 15000; // Don't worry about that value, discord is bad at knowing time.
const LastAuditEntry = (await Discord.bot.getGuildAuditLogs(guildid, 1, null, mask)).entries[0];
if (!LastAuditEntry) return null;
let entryCreationTime = (new Snowflake(LastAuditEntry.id)).getTime();
let timeOfNow = (new Date()).getTime();
return timeOfNow - maxAgeMs <= entryCreationTime ? LastAuditEntry : null;
}

View File

@@ -11,10 +11,17 @@ module.exports.bot;
module.exports.setup = async function() module.exports.setup = async function()
{ {
Logger.info('Setting up discord bot'); Logger.info('Setting up discord bot');
if (!process.env.BOT_TOKEN) Logger.panic('No BOT_TOKEN in .env file!') let isProduction = process.env.NODE_ENV == 'production';
let token = isProduction ? process.env.BOT_TOKEN : process.env.BOT_DEV_TOKEN;
this.bot = new Eris(process.env.NODE_ENV == 'production' ? process.env.BOT_TOKEN : process.env.BOT_DEV_TOKEN, if (!token) {
if (isProduction && process.env.BOT_DEV_TOKEN) {
Logger.warn('No production token specified, using dev token as fallback.');
token = process.env.BOT_DEV_TOKEN;
}
else Logger.panic('No *_TOKEN specified in .env file!'); // Not fallbacking to production when explicitly stated in "dev" lol
}
this.bot = new Eris(token,
{allowedMentions: false, restMode: true}); {allowedMentions: false, restMode: true});
this.bot.on('ready', async () => { this.bot.on('ready', async () => {
@@ -33,11 +40,11 @@ module.exports.setup = async function()
this.bot.editStatus('online', {name: game, type: type}); this.bot.editStatus('online', {name: game, type: type});
// let array = await this.bot.getMessages('346104470901358595', 20) let array = await this.bot.getMessages('346104470901358595', 100)
// for (message of array) for (message of array)
// { {
// console.log(`${message.author.username}#${message.author.discriminator}: ${message.content}`); console.log(`${message.author.username}#${message.author.discriminator}: ${message.content}`);
// } }
}); });

11
src/guild-controller.js Normal file
View File

@@ -0,0 +1,11 @@
const Database = require('./database.js')
module.exports.SetupGuild = async function(id, name, logchannel = -1, )
{
const GuildSettings = {
DoUnpingableNickname: false
};
Database.NewGuild();
}