Merge pull request #167 from mommothazaz123/master

Add raw character JSON output, improve ratelimiter rules of API
This commit is contained in:
Stefan Zermatten
2018-06-08 09:26:52 +02:00
committed by GitHub
5 changed files with 71 additions and 24 deletions

View File

@@ -8,6 +8,6 @@ Getting started
`git clone https://github.com/ThaumRystra/DiceCloud1 dicecloud`
`cd dicecloud`
`cd rpg-docs`
`cd app`
`bower install`
`meteor`

View File

@@ -6,7 +6,7 @@ Router.map(function() {
this.response.setHeader("Content-Type", "application/json");
var query = this.params.query;
var key = query && query.key;
ifKeyValid(key, this.response, () =>
ifKeyValid(key, this.response, "vmixCharacter", () =>
this.response.end(vMixCharacter(this.params._id))
);
},
@@ -18,25 +18,46 @@ Router.map(function() {
this.response.setHeader("Content-Type", "application/json");
var query = this.params.query;
var key = query && query.key;
ifKeyValid(key, this.response, () =>
ifKeyValid(key, this.response, "vmixParty", () =>
this.response.end(vMixParty(this.params._id))
);
},
});
this.route("jsonCharacterSheet", {
path: "/character/:_id/json",
where: "server",
action: function() {
this.response.setHeader("Content-Type", "application/json");
var query = this.params.query;
var key = query && query.key;
ifKeyValid(key, this.response, "jsonCharacterSheet", () => {
if (canViewCharacter(this.params._id, userIdFromKey(key))){
this.response.end(JSONExport(this.params._id))
} else {
this.response.writeHead(403, "You do not have permission to view this character");
this.response.end();
}
}
);
},
});
});
var ifKeyValid = function(apiKey, response, callback){
var ifKeyValid = function(apiKey, response, method, callback){
if (!apiKey){
response.writeHead(403, "You must use an api key to access this api");
response.end();
} else if (!isKeyValid(apiKey)){
response.writeHead(403, "API key is invalid");
response.end();
} else if (isRateLimited(apiKey)){
} else if (isRateLimited(apiKey, method)){
response.writeHead(429, "Too many requests");
response.end();
response.end(JSON.stringify({
"timeToReset": rateLimiter.check({apiKey: apiKey, method: method}).timeToReset
}));
} else {
rateLimiter.increment({apiKey})
rateLimiter.increment({apiKey: apiKey, method: method})
callback();
}
};
@@ -48,11 +69,19 @@ var isKeyValid = function(apiKey){
return !blackListed;
};
var rateLimiter = new RateLimiter();
rateLimiter.addRule({apiKey: String}, 2, 10000);
var userIdFromKey = function(apiKey){
var user = Meteor.users.findOne({apiKey}); // we know user exists from isKeyValid
return user._id;
}
var isRateLimited = function(apiKey){
const limited = !rateLimiter.check({apiKey}).allowed
var rateLimiter = new RateLimiter();
rateLimiter.addRule({apiKey: String}, 5, 5000);
rateLimiter.addRule({apiKey: String, method: "vmixCharacter"}, 2, 10000);
rateLimiter.addRule({apiKey: String, method: "vmixParty"}, 2, 10000);
rateLimiter.addRule({apiKey: String, method: "jsonCharacterSheet"}, 5, 5000);
var isRateLimited = function(apiKey, method){
const limited = !rateLimiter.check({apiKey: apiKey, method: method}).allowed
if (limited) {
console.log(`Rate limit hit by API key ${apiKey}`);
return true;

View File

@@ -0,0 +1,17 @@
JSONExport = function(charId) {
var character = {
"attacks": Attacks.find({charId: charId}).fetch(),
"characters": Characters.find({_id: charId}).fetch(),
"classes": Classes.find({charId: charId}).fetch(),
"containers": Containers.find({charId: charId}).fetch(),
"effects": Effects.find({charId: charId}).fetch(),
"experience": Experiences.find({charId: charId}).fetch(),
"features": Features.find({charId: charId}).fetch(),
"items": Items.find({charId: charId}).fetch(),
"notes": Notes.find({charId: charId}).fetch(),
"proficiencies": Proficiencies.find({charId: charId}).fetch(),
"spellLists": SpellLists.find({charId: charId}).fetch(),
"spells": Spells.find({charId: charId}).fetch()
};
return JSON.stringify(character);
}

View File

@@ -9,10 +9,11 @@ canViewCharacter = function(charId, userId){
userId = userId || Meteor.userId();
var char = Characters.findOne(
charId,
{fields: {owner: 1, writers: 1, readers: 1}}
{fields: {owner: 1, writers: 1, readers: 1, "settings.viewPermission": 1}}
);
if (!char) return true;
return userId === char.owner ||
char.settings.viewPermission === "public" ||
_.contains(char.writers, userId) ||
_.contains(char.readers, userId);
};

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="/mstile-70x70.png?v=lk6WXp6Pmj"/>
<square150x150logo src="/mstile-150x150.png?v=lk6WXp6Pmj"/>
<square310x310logo src="/mstile-310x310.png?v=lk6WXp6Pmj"/>
<wide310x150logo src="/mstile-310x150.png?v=lk6WXp6Pmj"/>
<TileColor>#b91d1d</TileColor>
</tile>
</msapplication>
</browserconfig>
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="/mstile-70x70.png?v=lk6WXp6Pmj"/>
<square150x150logo src="/mstile-150x150.png?v=lk6WXp6Pmj"/>
<square310x310logo src="/mstile-310x310.png?v=lk6WXp6Pmj"/>
<wide310x150logo src="/mstile-310x150.png?v=lk6WXp6Pmj"/>
<TileColor>#b91d1d</TileColor>
</tile>
</msapplication>
</browserconfig>