Use a token to protect POST API queries
This commit is contained in:
parent
20a162e915
commit
c5183a570f
@ -49,6 +49,8 @@ adapt the behavior to your needs.
|
||||
to `/`). The value should end with a trailing slash.
|
||||
* `THUNDERFOREST_API_KEY=` to pass an API key server to use for
|
||||
[Thunderforest](http://thunderforest.com/) tiles (OpenCycleMap, etc).
|
||||
* `API_TOKEN=` to pass a token required to access the server side API (check
|
||||
below in the server part environment variables for more details).
|
||||
|
||||
You should also have a look at the build variables under the `config/`
|
||||
subdirectory.
|
||||
@ -79,6 +81,7 @@ adapt its behavior:
|
||||
* `DATABASE=` to specify a [database URL](http://docs.peewee-orm.com/en/latest/peewee/playhouse.html#db-url) to connect to (defaults to
|
||||
`sqlite:///reports.db` which means a SQLite database named `reports.db` in
|
||||
the current working directory).
|
||||
* `API_TOKEN=` to specify a token required to `POST` data to the API.
|
||||
|
||||
#### Serving in production
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
'use strict'
|
||||
module.exports = {
|
||||
NODE_ENV: '"production"',
|
||||
API_BASE_URL: JSON.stringify(process.env.API_BASE_URL),
|
||||
THUNDERFOREST_API_KEY: JSON.stringify(process.env.THUNDERFOREST_API_KEY),
|
||||
NODE_ENV: '"production"',
|
||||
API_BASE_URL: JSON.stringify(process.env.API_BASE_URL),
|
||||
API_TOKEN: JSON.stringify(process.env.API_TOKEN),
|
||||
THUNDERFOREST_API_KEY: JSON.stringify(process.env.THUNDERFOREST_API_KEY),
|
||||
}
|
||||
|
@ -34,7 +34,8 @@ def enable_cors():
|
||||
'PUT, GET, POST, DELETE, OPTIONS, PATCH'
|
||||
)
|
||||
bottle.response.headers[str('Access-Control-Allow-Headers')] = str(
|
||||
'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
|
||||
'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token, '
|
||||
'Authorization'
|
||||
)
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@ Routes definitions
|
||||
"""
|
||||
import arrow
|
||||
import json
|
||||
import os
|
||||
|
||||
import bottle
|
||||
|
||||
@ -12,6 +13,29 @@ from server.models import Report
|
||||
from server import jsonapi
|
||||
|
||||
|
||||
class AuthenticationError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def check_auth():
|
||||
"""
|
||||
Check authentication.
|
||||
|
||||
:return: Abort and return a HTTP 403 page if authentication is not ok.
|
||||
"""
|
||||
if not os.getenv('API_TOKEN'):
|
||||
return
|
||||
|
||||
auth = bottle.request.headers.get('Authorization', None)
|
||||
if not auth:
|
||||
raise AuthenticationError()
|
||||
parts = auth.split()
|
||||
if parts[0].lower() != 'bearer' or parts[1] != os.getenv('API_TOKEN'):
|
||||
raise AuthenticationError()
|
||||
|
||||
return
|
||||
|
||||
|
||||
def get_reports(only_active=False):
|
||||
"""
|
||||
Get reports for the reports getting routes.
|
||||
@ -151,6 +175,12 @@ def post_report():
|
||||
if bottle.request.method == 'OPTIONS':
|
||||
return {}
|
||||
|
||||
# Check authentication
|
||||
try:
|
||||
check_auth()
|
||||
except AuthenticationError:
|
||||
return jsonapi.JsonApiError(403, "Invalid authentication.")
|
||||
|
||||
try:
|
||||
payload = json.load(bottle.request.body)
|
||||
except ValueError as exc:
|
||||
@ -189,6 +219,12 @@ def upvote_report(id):
|
||||
if bottle.request.method == 'OPTIONS':
|
||||
return {}
|
||||
|
||||
# Check authentication
|
||||
try:
|
||||
check_auth()
|
||||
except AuthenticationError:
|
||||
return jsonapi.JsonApiError(403, "Invalid authentication.")
|
||||
|
||||
r = Report.get(Report.id == id)
|
||||
if not r:
|
||||
return jsonapi.JsonApiError(404, "Invalid report id.")
|
||||
@ -213,6 +249,12 @@ def downvote_report(id):
|
||||
if bottle.request.method == 'OPTIONS':
|
||||
return {}
|
||||
|
||||
# Check authentication
|
||||
try:
|
||||
check_auth()
|
||||
except AuthenticationError:
|
||||
return jsonapi.JsonApiError(403, "Invalid authentication.")
|
||||
|
||||
r = Report.get(Report.id == id)
|
||||
if not r:
|
||||
return jsonapi.JsonApiError(404, "Invalid report id.")
|
||||
|
@ -3,6 +3,10 @@ require('isomorphic-fetch');
|
||||
|
||||
// With trailing slash
|
||||
export const BASE_URL = process.env.API_BASE_URL || '/';
|
||||
const AUTHORIZATION_HEADERS = new Headers({});
|
||||
if (process.env.API_TOKEN) {
|
||||
AUTHORIZATION_HEADERS.set('Authorization', `Bearer ${process.env.API_TOKEN}`);
|
||||
}
|
||||
|
||||
export function saveReport(type, lat, lng) {
|
||||
return fetch(`${BASE_URL}api/v1/reports`, {
|
||||
@ -12,6 +16,7 @@ export function saveReport(type, lat, lng) {
|
||||
lat,
|
||||
lng,
|
||||
}),
|
||||
headers: AUTHORIZATION_HEADERS,
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(response => response.data)
|
||||
@ -34,6 +39,7 @@ export function getActiveReports() {
|
||||
export function downvote(id) {
|
||||
return fetch(`${BASE_URL}api/v1/reports/${id}/downvote`, {
|
||||
method: 'POST',
|
||||
headers: AUTHORIZATION_HEADERS,
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(response => response.data)
|
||||
@ -46,6 +52,7 @@ export function downvote(id) {
|
||||
export function upvote(id) {
|
||||
return fetch(`${BASE_URL}api/v1/reports/${id}/upvote`, {
|
||||
method: 'POST',
|
||||
headers: AUTHORIZATION_HEADERS,
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(response => response.data)
|
||||
|
Loading…
Reference in New Issue
Block a user