Added API Key to secure future API endpoint.

pull/684/head
Louis Vézina 5 years ago
parent 3cdff1dd9f
commit 990d7e812c

@ -50,6 +50,14 @@ if not os.path.exists(os.path.join(args.config_dir, 'cache')):
configure_logging(settings.general.getboolean('debug') or args.debug) configure_logging(settings.general.getboolean('debug') or args.debug)
import logging import logging
# create random api_key if there's none in config.ini
if not settings.auth.apikey:
from binascii import hexlify
from six import text_type
settings.auth.apikey = text_type(hexlify(os.urandom(16)))
with open(os.path.join(args.config_dir, 'config', 'config.ini'), 'w+') as handle:
settings.write(handle)
# create database file # create database file
if not os.path.exists(os.path.join(args.config_dir, 'db', 'bazarr.db')): if not os.path.exists(os.path.join(args.config_dir, 'db', 'bazarr.db')):
import sqlite3 import sqlite3

@ -147,6 +147,16 @@ def authorize():
aaa.require(fail_redirect=(base_url + 'login')) aaa.require(fail_redirect=(base_url + 'login'))
def api_authorize():
if 'apikey' in request.GET.dict:
if request.GET.dict['apikey'][0] == settings.auth.apikey:
return
else:
abort(401, 'Unauthorized')
else:
abort(401, 'Unauthorized')
def post_get(name, default=''): def post_get(name, default=''):
return request.POST.get(name, default).strip() return request.POST.get(name, default).strip()
@ -1429,7 +1439,8 @@ def save_settings():
pass pass
else: else:
aaa._beaker_session.delete() aaa._beaker_session.delete()
settings.auth.apikey = request.forms.get('settings_auth_apikey')
settings_sonarr_ip = request.forms.get('settings_sonarr_ip') settings_sonarr_ip = request.forms.get('settings_sonarr_ip')
settings_sonarr_port = request.forms.get('settings_sonarr_port') settings_sonarr_port = request.forms.get('settings_sonarr_port')
settings_sonarr_baseurl = request.forms.get('settings_sonarr_baseurl') settings_sonarr_baseurl = request.forms.get('settings_sonarr_baseurl')
@ -2230,6 +2241,17 @@ def movie_history(no):
return dict(data=movie_history) return dict(data=movie_history)
# Don't put any route under this one
@route(base_url + 'api/help')
def api_help():
endpoints = []
for route in app.app.routes:
if '/api/' in route.rule:
endpoints.append(route.rule)
return dict(endpoints=endpoints)
# Mute DeprecationWarning # Mute DeprecationWarning
warnings.simplefilter("ignore", DeprecationWarning) warnings.simplefilter("ignore", DeprecationWarning)
server = CherryPyWSGIServer((str(settings.general.ip), (int(args.port) if args.port else int(settings.general.port))), app) server = CherryPyWSGIServer((str(settings.general.ip), (int(args.port) if args.port else int(settings.general.port))), app)

@ -116,7 +116,7 @@
.tab() .tab()
; ;
$('a:not(.tabs), button:not(.cancel, .test)').on('click', function(){ $('a:not(.tabs), button:not(.cancel, .test, .no_loader)').on('click', function(){
$('#loader').addClass('active'); $('#loader').addClass('active');
}); });

@ -328,6 +328,22 @@
</div> </div>
</div> </div>
</div> </div>
<div class="middle aligned row">
<div class="right aligned four wide column">
<label>API Key</label>
</div>
<div class="six wide column">
<div class='field'>
<div class="ui action input">
<input id="settings_auth_apikey" name="settings_auth_apikey" type="text" readonly value="{{settings.auth.apikey}}">
<button class="no_loader ui red icon button" type="button" onclick="generate_apikey()">
<i class="sync icon"></i>
</button>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
@ -866,3 +882,15 @@
</script> </script>
<script>
function generate_apikey() {
var result = '';
var characters = 'abcdef0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < 32; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
$( "#settings_auth_apikey" ).val( result );
}
</script>
Loading…
Cancel
Save