Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45e9f491ff | ||
|
|
742b26b0de | ||
|
|
164ba78c81 | ||
|
|
e27211b24d | ||
|
|
30987752cc | ||
|
|
4e574c0f51 | ||
|
|
80b195b7f7 |
9
rpg-docs/Model/Meta/Blacklist.js
Normal file
9
rpg-docs/Model/Meta/Blacklist.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Blacklist = new Mongo.Collection("blacklist");
|
||||||
|
|
||||||
|
Schemas.Blacklist = new SimpleSchema({
|
||||||
|
userId: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Blacklist.attachSchema(Schemas.Blacklist);
|
||||||
@@ -42,12 +42,21 @@ var ifKeyValid = function(apiKey, response, callback){
|
|||||||
};
|
};
|
||||||
|
|
||||||
var isKeyValid = function(apiKey){
|
var isKeyValid = function(apiKey){
|
||||||
return !!Meteor.users.findOne({apiKey});
|
var user = Meteor.users.findOne({apiKey});
|
||||||
|
if (!user) return false;
|
||||||
|
var blackListed = Blacklist.findOne({userId: user._id});
|
||||||
|
return !blackListed;
|
||||||
};
|
};
|
||||||
|
|
||||||
var rateLimiter = new RateLimiter();
|
var rateLimiter = new RateLimiter();
|
||||||
rateLimiter.addRule({apiKey: String}, 2, 10000);
|
rateLimiter.addRule({apiKey: String}, 2, 10000);
|
||||||
|
|
||||||
var isRateLimited = function(apiKey){
|
var isRateLimited = function(apiKey){
|
||||||
return !rateLimiter.check({apiKey}).allowed;
|
const limited = !rateLimiter.check({apiKey}).allowed
|
||||||
|
if (limited) {
|
||||||
|
console.log(`Rate limit hit by API key ${apiKey}`);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ Router.plugin("ensureSignedIn", {
|
|||||||
|
|
||||||
Router.plugin("dataNotFound", {notFoundTemplate: "notFound"});
|
Router.plugin("dataNotFound", {notFoundTemplate: "notFound"});
|
||||||
|
|
||||||
|
var handleSubError = function(e){
|
||||||
|
Session.set("error", {reason: e.reason, href: location.href});
|
||||||
|
Router.go("/error");
|
||||||
|
};
|
||||||
|
|
||||||
Router.map(function() {
|
Router.map(function() {
|
||||||
this.route("/", {
|
this.route("/", {
|
||||||
name: "home",
|
name: "home",
|
||||||
@@ -36,7 +41,9 @@ Router.map(function() {
|
|||||||
path: "/character/:_id/",
|
path: "/character/:_id/",
|
||||||
waitOn: function(){
|
waitOn: function(){
|
||||||
return [
|
return [
|
||||||
subsManager.subscribe("singleCharacter", this.params._id),
|
subsManager.subscribe(
|
||||||
|
"singleCharacter", this.params._id, {onError: handleSubError}
|
||||||
|
),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
action: function(){
|
action: function(){
|
||||||
@@ -52,7 +59,9 @@ Router.map(function() {
|
|||||||
path: "/character/:_id/:urlName",
|
path: "/character/:_id/:urlName",
|
||||||
waitOn: function(){
|
waitOn: function(){
|
||||||
return [
|
return [
|
||||||
subsManager.subscribe("singleCharacter", this.params._id),
|
subsManager.subscribe(
|
||||||
|
"singleCharacter", this.params._id, {onError: handleSubError}
|
||||||
|
),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
data: function() {
|
data: function() {
|
||||||
@@ -82,7 +91,9 @@ Router.map(function() {
|
|||||||
path: "/character/:_id/:urlName/print",
|
path: "/character/:_id/:urlName/print",
|
||||||
waitOn: function(){
|
waitOn: function(){
|
||||||
return [
|
return [
|
||||||
subsManager.subscribe("singleCharacter", this.params._id),
|
subsManager.subscribe(
|
||||||
|
"singleCharacter", this.params._id, {onError: handleSubError}
|
||||||
|
),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
data: function() {
|
data: function() {
|
||||||
@@ -153,4 +164,11 @@ Router.map(function() {
|
|||||||
document.title = appName;
|
document.title = appName;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.route("/error", {
|
||||||
|
name: "error",
|
||||||
|
onAfterAction: function() {
|
||||||
|
document.title = `${appName} - Error`;
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -133,6 +133,12 @@
|
|||||||
<div class="right clickable flex layout horizontal center">
|
<div class="right clickable flex layout horizontal center">
|
||||||
{{title}}
|
{{title}}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layout horizontal center">
|
||||||
|
<div class="layout vertical">
|
||||||
|
<paper-button class="resourceResetMax" disabled={{cantIncrement}}>Reset</paper-button>
|
||||||
|
<paper-button class="resourceResetZero" disabled={{cantDecrement}}>Clear</paper-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</paper-material>
|
</paper-material>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|||||||
@@ -111,6 +111,17 @@ Template.resource.helpers({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Template.resource.events({
|
Template.resource.events({
|
||||||
|
"click .resourceResetMax": function(event){
|
||||||
|
var modifier = {$set: {}};
|
||||||
|
modifier.$set[this.name + ".adjustment"] = 0;
|
||||||
|
Characters.update(this.char._id, modifier, {validate: false});
|
||||||
|
},
|
||||||
|
"click .resourceResetZero": function(event){
|
||||||
|
var base = Characters.calculate.attributeBase(this.char._id, this.name);
|
||||||
|
var modifier = {$set: {}};
|
||||||
|
modifier.$set[this.name + ".adjustment"] = -base;
|
||||||
|
Characters.update(this.char._id, modifier, {validate: false});
|
||||||
|
},
|
||||||
"click .resourceUp": function(event){
|
"click .resourceUp": function(event){
|
||||||
var value = Characters.calculate.attributeValue(this.char._id, this.name);
|
var value = Characters.calculate.attributeValue(this.char._id, this.name);
|
||||||
var base = Characters.calculate.attributeBase(this.char._id, this.name);
|
var base = Characters.calculate.attributeBase(this.char._id, this.name);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<div class="page">
|
<div class="page">
|
||||||
<div class="layout vertical" style="height: 100%;">
|
<div class="layout vertical" style="height: 100%;">
|
||||||
<div class="layout horizontal center" style="margin-bottom: 4mm">
|
<div class="layout horizontal center" style="margin-bottom: 4mm">
|
||||||
<img src="http://localhost:3000/crown-dice-logo-cropped-transparent.png" style="width: 60px; margin-right: 2mm">
|
<img src="/crown-dice-logo-cropped-transparent.png" style="width: 60px; margin-right: 2mm">
|
||||||
<div class="characterName paper-font-title" style="margin-right: 4mm">
|
<div class="characterName paper-font-title" style="margin-right: 4mm">
|
||||||
{{name}}
|
{{name}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
20
rpg-docs/client/views/meta/error/error.html
Normal file
20
rpg-docs/client/views/meta/error/error.html
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<template name="error">
|
||||||
|
<app-header-layout has-scrolling-region fullbleed>
|
||||||
|
<app-header class="app-grey white-text" fixed>
|
||||||
|
<app-toolbar>
|
||||||
|
<paper-icon-button icon="menu" drawer-toggle></paper-icon-button>
|
||||||
|
</app-toolbar>
|
||||||
|
</app-header>
|
||||||
|
<div class="fit layout vertical center center-justified">
|
||||||
|
<div class="paper-font-subhead"
|
||||||
|
style="margin-left: 16px;
|
||||||
|
margin-right: 16px;
|
||||||
|
text-align: center;">
|
||||||
|
{{#if errorMessage}}
|
||||||
|
<div>{{errorMessage}}</div>
|
||||||
|
<paper-button class="try-again">Try Again</paper-button>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</app-header-layout>
|
||||||
|
</template>
|
||||||
17
rpg-docs/client/views/meta/error/error.js
Normal file
17
rpg-docs/client/views/meta/error/error.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
Template.error.onRendered(function(){
|
||||||
|
const error = Session.get("error") || {};
|
||||||
|
if (error.href) window.history.replaceState("", "", error.href);
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.error.helpers({
|
||||||
|
errorMessage: function(){
|
||||||
|
const error = Session.get("error") || {};
|
||||||
|
return error.reason;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.error.events({
|
||||||
|
"click .try-again": function(event, instance){
|
||||||
|
window.location.reload();
|
||||||
|
},
|
||||||
|
});
|
||||||
8
rpg-docs/server/lib/logRateError.js
Normal file
8
rpg-docs/server/lib/logRateError.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
logRateError = function(reply, ruleInput){
|
||||||
|
// reply = {allowed, timeToReset, numInvocationsLeft}
|
||||||
|
// ruleInput = {userId, clientAddress, type, name, connectionId}
|
||||||
|
console.log(
|
||||||
|
`Limit hit for ${ruleInput.type} "${ruleInput.name}" ` +
|
||||||
|
`by user ${ruleInput.userId} from ${ruleInput.clientAddress}`
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -38,9 +38,13 @@ Meteor.publish("singleCharacter", function(characterId){
|
|||||||
DDPRateLimiter.addRule({
|
DDPRateLimiter.addRule({
|
||||||
name: "singleCharacter",
|
name: "singleCharacter",
|
||||||
type: "subscription",
|
type: "subscription",
|
||||||
userId(){ return true; },
|
userId: null,
|
||||||
connectionId(){ return true; },
|
connectionId(){ return true; },
|
||||||
}, 8, 5000);
|
}, 8, 10000, function(reply, ruleInput){
|
||||||
|
if(!reply.allowed){
|
||||||
|
logRateError(reply, ruleInput);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Meteor.publish("singleCharacterName", function(characterId){
|
Meteor.publish("singleCharacterName", function(characterId){
|
||||||
userId = this.userId;
|
userId = this.userId;
|
||||||
|
|||||||
Reference in New Issue
Block a user