Security fixes (#32)

* Generic Object Injection Sink

* (fix) "Character" is not defined.

* added eslint

* improve code quality, use refactored function

* (fix) eslint jest

* "Character" is not defined

* removed unused file Compare.js

* (fix) PointsUsed is not defined

* (fix) eslint moans jsconfig

* turn off "no-prototype-builtins"

* push code coverage
This commit is contained in:
2021-05-01 20:13:15 +02:00
committed by GitHub
parent 63bd06e92f
commit d45e4faad6
20 changed files with 413 additions and 261 deletions

75
.eslintrc.json Normal file
View File

@ -0,0 +1,75 @@
{
"parserOptions": {
"ecmaVersion": 10,
"sourceType": "script",
"ecmaFeatures": {
"jsx": true
}
},
"rules": {
"constructor-super": 2,
"for-direction": 2,
"getter-return": 2,
"no-async-promise-executor": 2,
"no-case-declarations": 2,
"no-class-assign": 2,
"no-compare-neg-zero": 2,
"no-cond-assign": 2,
"no-const-assign": 2,
"no-constant-condition": 2,
"no-control-regex": 2,
"no-debugger": 2,
"no-delete-var": 2,
"no-dupe-args": 2,
"no-dupe-class-members": 2,
"no-dupe-else-if": 2,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-empty": 2,
"no-empty-character-class": 2,
"no-empty-pattern": 2,
"no-ex-assign": 2,
"no-extra-boolean-cast": 2,
"no-extra-semi": 2,
"no-fallthrough": 2,
"no-func-assign": 2,
"no-global-assign": 2,
"no-import-assign": 2,
"no-inner-declarations": 2,
"no-invalid-regexp": 2,
"no-irregular-whitespace": 2,
"no-misleading-character-class": 2,
"no-mixed-spaces-and-tabs": 2,
"no-new-symbol": 2,
"no-obj-calls": 2,
"no-octal": 2,
"no-prototype-builtins": 0,
"no-redeclare": 2,
"no-regex-spaces": 2,
"no-self-assign": 2,
"no-setter-return": 2,
"no-shadow-restricted-names": 2,
"no-sparse-arrays": 2,
"no-this-before-super": 2,
"no-undef": 2,
"no-unexpected-multiline": 2,
"no-unreachable": 2,
"no-unsafe-finally": 2,
"no-unsafe-negation": 2,
"no-unused-labels": 2,
"no-unused-vars": 2,
"no-useless-catch": 2,
"no-useless-escape": 2,
"no-with": 2,
"require-yield": 2,
"use-isnan": 2,
"valid-typeof": 2
},
"env": {
"node": true,
"jest": true,
"commonjs": true,
"es2017": true
},
"extends": ["prettier"]
}

View File

@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node-version: [10.x, 12.x, 14.x, 15.x] node-version: [15.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/ # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -30,6 +30,10 @@ jobs:
- run: npm ci - run: npm ci
- run: npm run build --if-present - run: npm run build --if-present
- run: npm test - run: npm test
- name: Run codacy-coverage-reporter
uses: codacy/codacy-coverage-reporter-action@v1
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
deploy: deploy:

View File

@ -1,6 +1,6 @@
# DSA Discord Bot # DSA Discord Bot
![GitHub package.json version](https://img.shields.io/github/package-json/v/TobenderZephyr/dsabot?style=flat-square) ![node-current](https://img.shields.io/node/v/discord.js?style=flat-square) ![GitHub last commit](https://img.shields.io/github/last-commit/TobenderZephyr/dsabot?style=flat-square) ![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/TobenderZephyr/dsabot-docker/Build%20Image%20on%20Push/main?label=docker%20image&style=flat-square) ![Docker Pulls](https://img.shields.io/docker/pulls/tobenderzephyr/dsabot) [![CodeQL](https://github.com/TobenderZephyr/dsabot/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/TobenderZephyr/dsabot/actions/workflows/codeql-analysis.yml) ![GitHub package.json version](https://img.shields.io/github/package-json/v/TobenderZephyr/dsabot?style=flat-square) ![node-current](https://img.shields.io/node/v/discord.js?style=flat-square) ![GitHub last commit](https://img.shields.io/github/last-commit/TobenderZephyr/dsabot?style=flat-square) ![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/TobenderZephyr/dsabot-docker/Build%20Image%20on%20Push/main?label=docker%20image&style=flat-square) ![Docker Pulls](https://img.shields.io/docker/pulls/tobenderzephyr/dsabot) [![CodeQL](https://github.com/TobenderZephyr/dsabot/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/TobenderZephyr/dsabot/actions/workflows/codeql-analysis.yml) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/565f705cf4a8403387b55c559a7bf5bc)](https://www.codacy.com/gh/TobenderZephyr/dsabot/dashboard?utm_source=github.com&utm_medium=referral&utm_content=TobenderZephyr/dsabot&utm_campaign=Badge_Grade)
This Project is a fork of LucaSchwan/dsa-bot. This Project is a fork of LucaSchwan/dsa-bot.

View File

@ -139,7 +139,7 @@ it('should abort with a message: no entry found', () => {
}; };
const handleAttack = rewireUtils.__get__('handleAttack'); const handleAttack = rewireUtils.__get__('handleAttack');
//expect(handleAttack(err)).toThrowError(); //expect(handleAttack(err)).toThrowError();
expect(handleAttack(null, [], { message: message })).toEqual( expect(handleAttack([], { message: message })).toEqual(
'Sorry, für dich habe ich leider keinen Eintrag 😥' 'Sorry, für dich habe ich leider keinen Eintrag 😥'
); );
}); });
@ -152,7 +152,7 @@ it('should abort with a message: No such weapon', () => {
}; };
const handleAttack = rewireUtils.__get__('handleAttack'); const handleAttack = rewireUtils.__get__('handleAttack');
const args = ['']; const args = [''];
expect(handleAttack(null, [{ character: {} }], { message: message, args: args })).toEqual( expect(handleAttack([{ character: {} }], { message: message, args: args })).toEqual(
'Diese Waffe gibt es nicht.' 'Diese Waffe gibt es nicht.'
); );
}); });
@ -178,9 +178,9 @@ it('complete run with melee weapon', () => {
}; };
const handleAttack = rewireUtils.__get__('handleAttack'); const handleAttack = rewireUtils.__get__('handleAttack');
const args = ['messer']; const args = ['messer'];
expect( expect(handleAttack([{ character: character }], { message: message, args: args })).toEqual(
handleAttack(null, [{ character: character }], { message: message, args: args }) expect.any(String)
).toEqual(expect.any(String)); );
}); });
it('complete run with ranged weapon', () => { it('complete run with ranged weapon', () => {
@ -204,7 +204,7 @@ it('complete run with ranged weapon', () => {
}; };
const handleAttack = rewireUtils.__get__('handleAttack'); const handleAttack = rewireUtils.__get__('handleAttack');
const args = ['langbogen']; const args = ['langbogen'];
expect( expect(handleAttack([{ character: character }], { message: message, args: args })).toEqual(
handleAttack(null, [{ character: character }], { message: message, args: args }) expect.any(String)
).toEqual(expect.any(String)); );
}); });

View File

@ -17,8 +17,17 @@ const TestValues = [
[13, 5], [13, 5],
[14, 5], [14, 5],
[15, 5], [15, 5],
[16, 6],
[17, 6],
[18, 6],
[19, 6],
[20, 6],
]; ];
test.each(TestValues)('Retrieving Quality for %s', (input, output) => { test.each(TestValues)('Retrieving Quality for %s', (input, output) => {
expect(CalculateQuality(input)).toBe(output); expect(CalculateQuality(input)).toBe(output);
}); });
it('should return 1 without input', () => {
expect(CalculateQuality()).toBe(1);
});

View File

@ -4,3 +4,7 @@ const { Capitalize } = require('@dsabot/Capitalize');
it('should capitalize the first letter.', () => { it('should capitalize the first letter.', () => {
expect(Capitalize('mother')).toBe('Mother'); expect(Capitalize('mother')).toBe('Mother');
}); });
it('should capitalize without any word given', () => {
expect(Capitalize()).toBe('None');
});

View File

@ -7,3 +7,13 @@ it('turn any number into a string', () => {
expect(f(0)).toBe('0'); expect(f(0)).toBe('0');
expect(f(-1)).toBe('-1'); expect(f(-1)).toBe('-1');
}); });
it('should return a string', () => {
const obj = {
Attributes: [8, 8, 8],
Throws: [7, 7, 7],
PointsUsed: [0, 0, 0],
Bonus: 0,
};
expect(CreateResultTable(obj)).toEqual(expect.any(String));
});

View File

@ -13,16 +13,21 @@ module.exports = {
async exec(message, args) { async exec(message, args) {
try { try {
db.find({ user: message.author.tag }, (err, docs) => db.find({ user: message.author.tag }, (err, docs) => {
handleAttack(err, docs, { message: message, args: args }) if (err) {
); message.reply(findMessage('ERROR'));
throw new Error(err);
}
handleAttack(docs, { message: message, args: args });
});
} catch (e) { } catch (e) {
message.reply(findMessage('ERROR'));
throw e; throw e;
} }
}, },
}; };
function handleAttack(err, docs, { message: message, args: args }) { function handleAttack(docs, { message: message, args: args }) {
if (docs.length === 0) { if (docs.length === 0) {
return message.reply(findMessage('NOENTRY')); return message.reply(findMessage('NOENTRY'));
} }

View File

@ -1,6 +1,5 @@
const globals = require('../globals'); const globals = require('../globals');
const { CountOccurences } = require('@dsabot/CountOccurences'); const { CountOccurences } = require('@dsabot/CountOccurences');
const { findMessage } = require('@dsabot/findMessage');
const Random = require('random'); const Random = require('random');
const db = globals.db; const db = globals.db;
@ -11,19 +10,19 @@ module.exports = {
usage: '<Eigenschaft> / <Eigenschaftswert>', usage: '<Eigenschaft> / <Eigenschaftswert>',
needs_args: true, needs_args: true,
async exec(message, args) { async exec(message, args) {
try {
let Attribute; let Attribute;
let AttributeName; let AttributeName;
let Level = 8; let Level = 8;
await db.find({ await db.find(
{
user: message.author.tag, user: message.author.tag,
}, async (err, docs) => { },
async (err, docs) => {
// user calls with text, let's look him up in the database. // user calls with text, let's look him up in the database.
if (isNaN(args[0])) { if (isNaN(args[0])) {
Attribute = HandleNamedAttributes({ Attribute = HandleNamedAttributes({
Character: docs[0].character, Character: docs[0].character,
args: args args: args,
}); });
AttributeName = Attribute.Name; AttributeName = Attribute.Name;
Level = Attribute.Level; Level = Attribute.Level;
@ -34,63 +33,84 @@ module.exports = {
const dice = []; const dice = [];
dice.push(Random.int(1, 20)); dice.push(Random.int(1, 20));
if (dice[0] == 1 || dice[0] == 20) { if (dice[0] === 1 || dice[0] === 20) {
dice.push(Random.int(1, 20)); dice.push(Random.int(1, 20));
} }
// handle crits // handle crits
if (CountOccurences(dice, 1) == 2) { if (CountOccurences(dice, 1) === 2) {
message.reply('Du hast einen kritischen Erfolg erzielt (' + dice.join(', ') + ')! 🎉🥳🎆'); message.reply(
`Du hast einen kritischen Erfolg erzielt (${dice.join(', ')})! 🎉🥳🎆`
);
return; return;
} else if (CountOccurences(dice, 20) == 2) { } else if (CountOccurences(dice, 20) === 2) {
message.reply('Du hast einen Patzer (' + dice.join(', ') + ')! 😭 Viel Erfolg beim nächsten mal!'); message.reply(
'Du hast einen Patzer (' +
dice.join(', ') +
')! 😭 Viel Erfolg beim nächsten mal!'
);
return; return;
} }
if ((dice.length == 2 && dice[0] != 20 && dice[1] <= Level) || (dice.length == 1 && dice[0] <= Level)) { if (
(dice.length == 2 && dice[0] != 20 && dice[1] <= Level) ||
(dice.length == 1 && dice[0] <= Level)
) {
if (AttributeName) { if (AttributeName) {
message.reply('Du hast die Probe auf ' + AttributeName + ' (Stufe ' + Level + ') bestanden.\n' + message.reply(
'Deine 🎲: ' + dice.join(', ')); 'Du hast die Probe auf ' +
AttributeName +
' (Stufe ' +
Level +
') bestanden.\n' +
'Deine 🎲: ' +
dice.join(', ')
);
} else { } else {
message.reply('Du hast die Probe (Stufe ' + Level + ') bestanden.\n' + message.reply(
'Deine 🎲: ' + dice.join(', ')); 'Du hast die Probe (Stufe ' +
Level +
') bestanden.\n' +
'Deine 🎲: ' +
dice.join(', ')
);
} }
} else if (AttributeName) { } else if (AttributeName) {
message.reply('Du hast die Probe auf ' + AttributeName + ' (Stufe ' + Level + ') leider nicht bestanden 😢.\n' + message.reply(
'Deine 🎲: ' + dice.join(', ')); 'Du hast die Probe auf ' +
AttributeName +
' (Stufe ' +
Level +
') leider nicht bestanden 😢.\n' +
'Deine 🎲: ' +
dice.join(', ')
);
} else { } else {
message.reply('Du hast die Probe (Stufe ' + Level + ') leider nicht bestanden 😢.\n' + message.reply(
'Deine 🎲: ' + dice.join(', ')); `Du hast die Probe (Stufe ${Level}) leider nicht bestanden 😢.\nDeine 🎲: ${dice.join(
', '
)}`
);
} }
});
} catch (e) {
throw e;
} }
);
}, },
}; };
const HandleCrits = (dice) => { function HandleNamedAttributes({ Character: Character = [], args: args = [] } = {}) {
let Attribute = getAttribute(args[0]);
}; let Level = getAttributeLevel(Character, Attribute) || 8;
const HandleNamedAttributes = ({Character: Character = [], args: args = []} = {}) => {
let Attributes = globals.Werte;
let Level = 8; // This is the minimum attributes value.
let AttributeName;
let AttributeId;
if (args[0].length == 2) {
AttributeId = Attributes.find(attribute => attribute.kuerzel === args[0].toUpperCase()).id;
} else {
AttributeId = args[0].toLowerCase() ||
Attributes.find(attribute => attribute.name.toLowerCase() === args[0].toLowerCase()).id;
}
Level = Character.attributes.find(attribute => attribute.id === AttributeId).level;
AttributeName = Attributes.find(attribute => attribute.id === AttributeId).name;
return { return {
Name: AttributeName, Name: Attribute.name,
Level: Level Level: Level,
}; };
}
}; function getAttributeLevel(Character = {}, Attribute = {}) {
return Character.attributes.find(attribute => attribute.id === Attribute.id).level;
}
function getAttribute(attribute = '') {
return attribute.length === 2
? globals.Werte.find(a => a.kuerzel === attribute.toUpperCase())
: globals.Werte.find(a => a.name.toLowerCase() === attribute.toLowerCase());
}

View File

@ -16,7 +16,7 @@ module.exports = {
if (docs.length === 0) { if (docs.length === 0) {
return message.reply(findMessage('NOENTRY')); return message.reply(findMessage('NOENTRY'));
} }
Character = docs[0].character; const Character = docs[0].character;
if (!Character.hasOwnProperty('chants')) return message.reply(findMessage('NO_CHANTS')); if (!Character.hasOwnProperty('chants')) return message.reply(findMessage('NO_CHANTS'));
if (args.length === 0) { if (args.length === 0) {
const Embed = new Discord.MessageEmbed() const Embed = new Discord.MessageEmbed()

View File

@ -3,14 +3,18 @@ const globals = require('../globals');
const db = globals.db; const db = globals.db;
module.exports = { module.exports = {
name: 'remove', name: 'remove',
description: 'Löscht deinen Charakter aus der Datenbank. Sinnvoll, wenn du mir eine neue zusenden möchtest.', description:
'Löscht deinen Charakter aus der Datenbank. Sinnvoll, wenn du mir eine neue zusenden möchtest.',
aliases: [], aliases: [],
usage: '', usage: '',
needs_args: false, needs_args: false,
// eslint-disable-next-line no-unused-vars
async exec(message, args) { async exec(message, args) {
db.remove({ db.remove({ user: message.author.tag }, err => {
user: message.author.tag, if (err) {
}, {}, function(err, numRemoved) { message.reply(findMessage('ERROR'));
throw new Error(err);
}
return message.reply(findMessage('DELETED_DATA')); return message.reply(findMessage('DELETED_DATA'));
}); });
}, },

View File

@ -11,30 +11,38 @@ module.exports = {
usage: '', usage: '',
needs_args: false, needs_args: false,
// eslint-disable-next-line no-unused-vars
async exec(message, args) { async exec(message, args) {
try { try {
db.find({ db.find(
{
user: message.author.tag, user: message.author.tag,
}, function(err, docs) { },
function (err, docs) {
if (docs.length === 0) { if (docs.length === 0) {
return message.reply(findMessage('NOENTRY')); return message.reply(findMessage('NOENTRY'));
} } else {
else {
const Character = docs[0].character; const Character = docs[0].character;
let Gender; let Gender;
if (Character.sex == 'female') { Gender = '♀️'; } if (Character.sex == 'female') {
else { Gender = ''; } Gender = '';
} else {
Gender = '♂️';
}
const Reply = new Discord.MessageEmbed(); const Reply = new Discord.MessageEmbed();
Reply.setColor('#0099ff'); Reply.setColor('#0099ff');
Reply.setTitle(`${Gender} ${Character.name}`); Reply.setTitle(`${Gender} ${Character.name}`);
Reply.setDescription(`${Character.age} Jahre, ${Character.race}/${Character.culture}`); Reply.setDescription(
`${Character.age} Jahre, ${Character.race}/${Character.culture}`
);
Reply.addField(Character.professionname, Character.xp.startinglevel); Reply.addField(Character.professionname, Character.xp.startinglevel);
message.reply(Reply); message.reply(Reply);
} }
});
} }
catch (e) { );
} catch (e) {
message.reply(findMessage('ERROR'));
throw e; throw e;
} }
}, },

View File

@ -16,7 +16,7 @@ module.exports = {
if (docs.length === 0) { if (docs.length === 0) {
return message.reply(findMessage('NOENTRY')); return message.reply(findMessage('NOENTRY'));
} }
Character = docs[0].character; const Character = docs[0].character;
if (!Character.hasOwnProperty('spells')) return message.reply(findMessage('NO_SPELLS')); if (!Character.hasOwnProperty('spells')) return message.reply(findMessage('NO_SPELLS'));
if (args.length === 0) { if (args.length === 0) {
const Embed = new Discord.MessageEmbed() const Embed = new Discord.MessageEmbed()
@ -52,6 +52,8 @@ const ReplySpell = (Spell = {}) => {
const createSpellList = (Character = {}) => { const createSpellList = (Character = {}) => {
if (!Character || !Character.hasOwnProperty('spells')) return; if (!Character || !Character.hasOwnProperty('spells')) return;
let SpellList = []; let SpellList = [];
Character.spells.forEach(spell => SpellList.push(getSpell({ Character: Character, spell_name: spell.id }))); Character.spells.forEach(spell =>
SpellList.push(getSpell({ Character: Character, spell_name: spell.id }))
);
return SpellList.filter(value => value !== undefined); //?+ return SpellList.filter(value => value !== undefined); //?+
}; };

View File

@ -1,85 +1,64 @@
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const Random = require('random');
const globals = require('../globals');
const Discord = require('discord.js'); const Discord = require('discord.js');
const { roll } = require('@dsabot/Roll'); const { roll } = require('@dsabot/Roll');
const { findMessage } = require('@dsabot/findMessage'); const { findMessage } = require('@dsabot/findMessage');
const { CompareResults } = require('@dsabot/CompareResults');
module.exports = { module.exports = {
name: 'tp', name: 'tp',
description: 'Du machst eine Fertigkeitsprobe.\n' + description:
'Du machst eine Fertigkeitsprobe.\n' +
' Es werden drei Würfel auf deine Eigenschaftswerte geworfen. Hast du Boni auf dein Talent und/oder' + ' Es werden drei Würfel auf deine Eigenschaftswerte geworfen. Hast du Boni auf dein Talent und/oder' +
' ist der Wurf erleichtert oder erschwert, wird dies in die Berechnung einbezogen.', ' ist der Wurf erleichtert oder erschwert, wird dies in die Berechnung einbezogen.',
aliases: ['talentprobe'], aliases: ['talentprobe'],
usage: '<Eigenschaftswert1> <Eigenschaftswert2> <Eigenschaftswert3> [<Fertigkeitswert>] [<-Erschwernis> / <+Erleichterung>]', usage:
'<Eigenschaftswert1> <Eigenschaftswert2> <Eigenschaftswert3> [<Fertigkeitswert>] [<-Erschwernis> / <+Erleichterung>]',
needs_args: true, needs_args: true,
async exec(message, args) { async exec(message, args) {
if (isNaN(args[0])) { if (isNaN(args[0])) {
return message.reply(findMessage('WRONG_ARGUMENTS')); return message.reply(findMessage('WRONG_ARGUMENTS'));
} }
//Random.use(message.author.tag); let Bonus = parseInt(args[3]) || 0;
//const dice = []; let Erschwernis = parseInt(args[4]) || 0;
let bonus = 0;
let bonus_orig = 0;
let erschwernis = 0;
if (args[3]) {
bonus_orig = parseInt(args[3]);
bonus = bonus_orig;
}
if (args[4]) {
erschwernis = parseInt(args[4]);
}
/*for (let i = 1; i <= 3; i++) {
roll.push(Random.int(1, 20));
}*/
const dice = roll(3, 20, message.author.tag).dice; const dice = roll(3, 20, message.author.tag).dice;
let ok = 0; const {
let patzer = 0; Passed: Passed,
let crit = 0; CriticalHit: CriticalHit,
for (let i = 0; i < 3; i++) { Fumbles: Fumbles,
if (Math.floor(parseInt(args[i]) + parseInt(erschwernis)) >= dice[i]) { PointsRemaining: PointsRemaining} = CompareResults(dice, [args[0], args[1], args[2]], Bonus, Erschwernis);
ok++;
} else if (
Math.floor(parseInt(args[i]) + parseInt(bonus) + parseInt(erschwernis)) >= dice[i]) {
ok++;
bonus = bonus - (dice[i] - parseInt(erschwernis) - parseInt(args[i]));
}
if (dice[i] == 1) {crit++;}
if (dice[i] == 20) {patzer++;}
}
const Reply = new Discord.MessageEmbed(); const Reply = new Discord.MessageEmbed();
Reply.setTitle(`${findMessage('ROLL')} ${dice.join(', ')}.`); Reply.setTitle(`${findMessage('ROLL')} ${dice.join(', ')}.`);
if (patzer >= 2) { if (Fumbles >= 2) {
Reply.setColor('#900c3f'); Reply.setColor('#900c3f');
Reply.addFields({ Reply.addFields({
name: findMessage('TITLE_CRIT_FAILURE'), name: findMessage('TITLE_CRIT_FAILURE'),
value: findMessage('MSG_CRIT_FAILURE'), value: findMessage('MSG_CRIT_FAILURE'),
inline: false inline: false,
}); });
} else if (crit >= 2) { } else if (CriticalHit >= 2) {
Reply.setColor('#1E8449'); Reply.setColor('#1E8449');
Reply.addFields({ Reply.addFields({
name: findMessage('TITLE_CRIT_SUCCESS'), name: findMessage('TITLE_CRIT_SUCCESS'),
value: findMessage('MSG_CRIT_SUCCESS'), value: findMessage('MSG_CRIT_SUCCESS'),
inline: false inline: false,
}); });
} else if (ok < 3) { } else if (Passed < 3) {
Reply.addFields({ Reply.addFields({
name: findMessage('TITLE_FAILURE'), name: findMessage('TITLE_FAILURE'),
value: 'Nur ' + ok + '/3 Proben erfolgreich. 😪', value: `${Passed ? `Nur ${Passed}/3 Proben` : `Keine Probe`} erfolgreich. 😪`,
inline: false inline: false,
}); });
} else { } else {
Reply.addFields({ Reply.addFields({
name: findMessage('TITLE_SUCCESS'), name: findMessage('TITLE_SUCCESS'),
value: ok + '/3 Proben erfolgreich. Dein Bonus: ' + bonus + '/' + bonus_orig + '.', value: `${Passed}/3 Proben erfolgreich. Dein Bonus: ${PointsRemaining}/${Bonus}`,
inline: false inline: false,
}); });
} }
message.reply(Reply); message.reply(Reply);
} },
}; };

View File

@ -1,15 +1,9 @@
const CalculateQuality = (PointsAvailable = 0) => { const CalculateQuality = (PointsAvailable = 0) => {
if (PointsAvailable <= 3) if (PointsAvailable <= 3) return 1;
return 1; else if (PointsAvailable > 3 && PointsAvailable <= 6) return 2;
else if (PointsAvailable > 3 && PointsAvailable <= 6) else if (PointsAvailable > 6 && PointsAvailable <= 9) return 3;
return 2; else if (PointsAvailable > 9 && PointsAvailable <= 12) return 4;
else if (PointsAvailable > 6 && PointsAvailable <= 9) else if (PointsAvailable > 12 && PointsAvailable <= 15) return 5;
return 3; else return 6;
else if (PointsAvailable > 9 && PointsAvailable <= 12)
return 4;
else if (PointsAvailable > 12 && PointsAvailable <= 15)
return 5;
else if (PointsAvailable > 15)
return 6;
}; };
module.exports = { CalculateQuality }; module.exports = { CalculateQuality };

View File

@ -1,6 +0,0 @@
const Compare = () => {
return { result };
};
module.exports = { Compare };

View File

@ -18,28 +18,28 @@ const CompareResults = (
let CriticalHit = 0; let CriticalHit = 0;
let AllPointsUsed = []; let AllPointsUsed = [];
for (let i = 0; i < Throws.length; i++) { Throws.forEach((Throw, key) => {
let PointsUsed = 0; let PointsUsed = 0;
if (Math.floor(AttributeLevels[i] + Bonus) >= Throws[i]) { let AttributeLevel = AttributeLevels.find((v, k) => key === k);
if (Math.floor(AttributeLevel + Bonus) >= Throw) {
Passed++; Passed++;
} else if (Math.floor(AttributeLevels[i] + PointsRemaining + Bonus) >= Throws[i]) { } else if (Math.floor(AttributeLevel + PointsRemaining + Bonus) >= Throw) {
Passed++; Passed++;
PointsUsed = Throws[i] - Bonus - AttributeLevels[i]; PointsUsed = Throw - Bonus - AttributeLevel;
PointsRemaining -= PointsUsed; PointsRemaining -= PointsUsed;
} else { } else {
// We need to use all our points, so that next die/dice
// would not return a 'Passed'.
PointsUsed = PointsRemaining; PointsUsed = PointsRemaining;
PointsRemaining -= PointsUsed; PointsRemaining -= PointsUsed;
} }
if (Throws[i] == 1) { if (Throw === 1) {
CriticalHit++; CriticalHit++;
} }
if (Throws[i] == 20) { if (Throw === 20) {
Fumbles++; Fumbles++;
} }
AllPointsUsed.push(PointsUsed); AllPointsUsed.push(PointsUsed);
} });
return { return {
Passed: Passed, Passed: Passed,
CriticalHit: CriticalHit, CriticalHit: CriticalHit,

View File

@ -7,10 +7,10 @@
"@data/*": ["./data/*"], "@data/*": ["./data/*"],
"@Commands/*": ["./commands/*"], "@Commands/*": ["./commands/*"],
"@Lib/*": ["./lib/*"] "@Lib/*": ["./lib/*"]
}, }
}, },
"exclude": ["node_modules"], "exclude": ["node_modules"],
"typeAcquisition": { "typeAcquisition": {
"exclude": ["dotenv", "source-map"] "exclude": ["dotenv", "source-map"]
}, }
} }

45
package-lock.json generated
View File

@ -1,11 +1,11 @@
{ {
"name": "dsabot", "name": "dsabot",
"version": "1.5.0", "version": "1.5.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"version": "1.5.0", "version": "1.5.2",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"discord.js": "^12.5.3", "discord.js": "^12.5.3",
@ -17,6 +17,8 @@
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^26.0.23", "@types/jest": "^26.0.23",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.8.0",
"jest": "^26.6.3", "jest": "^26.6.3",
"rewire": "^5.0.0" "rewire": "^5.0.0"
} }
@ -2027,6 +2029,21 @@
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/eslint-config-prettier": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.8.0.tgz",
"integrity": "sha512-aq4M7mjjVregZ2l45O9qz6Mv6f5zVMl/IqfmUL8hNOoDAzVKYMhYPJytbqE/lPIVO1iMDXIFqjiEE59BfJZpZw==",
"dev": true,
"dependencies": {
"get-stdin": "^6.0.0"
},
"bin": {
"eslint-config-prettier-check": "bin/cli.js"
},
"peerDependencies": {
"eslint": ">=3.14.1"
}
},
"node_modules/eslint-scope": { "node_modules/eslint-scope": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@ -2857,6 +2874,15 @@
"node": ">=8.0.0" "node": ">=8.0.0"
} }
}, },
"node_modules/get-stdin": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
"integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/get-stream": { "node_modules/get-stream": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
@ -8924,6 +8950,15 @@
} }
} }
}, },
"eslint-config-prettier": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.8.0.tgz",
"integrity": "sha512-aq4M7mjjVregZ2l45O9qz6Mv6f5zVMl/IqfmUL8hNOoDAzVKYMhYPJytbqE/lPIVO1iMDXIFqjiEE59BfJZpZw==",
"dev": true,
"requires": {
"get-stdin": "^6.0.0"
}
},
"eslint-scope": { "eslint-scope": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@ -9423,6 +9458,12 @@
"integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
"dev": true "dev": true
}, },
"get-stdin": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
"integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
"dev": true
},
"get-stream": { "get-stream": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",

View File

@ -6,7 +6,7 @@
"scripts": { "scripts": {
"lint": "eslint commands/", "lint": "eslint commands/",
"start": "node index.js", "start": "node index.js",
"test": "jest" "test": "jest --collectCoverage"
}, },
"_moduleAliases": { "_moduleAliases": {
"@dsabot": "functions", "@dsabot": "functions",
@ -26,6 +26,8 @@
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^26.0.23", "@types/jest": "^26.0.23",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.8.0",
"jest": "^26.6.3", "jest": "^26.6.3",
"rewire": "^5.0.0" "rewire": "^5.0.0"
}, },
@ -35,6 +37,7 @@
"**/*.{js,jsx}", "**/*.{js,jsx}",
"!**/node_modules/**", "!**/node_modules/**",
"!**/vendor/**" "!**/vendor/**"
] ],
"coverageDirectory": "coverage"
} }
} }