2638: further finishing touches for restful api r=mergify[bot] a=Diman0

- Fix setup utility setting correct value to env var API. It now also sets `false` when the API is disabled in the setup utility.
- Fix IF statement for enabling API in nginx.conf. Setting a different value than `API=true` in mailu.env now disabled the API endpoint in nginx.
- Use safer command for regenerating example API token. It uses crypto.getRandomValues() (as suggested by nextgens) which should be more random than the previously used method. 

## What type of PR?

bug-fix

## What does this PR do?

### Related issue(s)

## Prerequisites
Before we can consider review and merge, please make sure the following list is done and checked.
If an entry in not applicable, you can check it or remove it from the list.

- [ ] In case of feature or enhancement: documentation updated accordingly
- [ ] Unless it's docs or a minor change: add [changelog](https://mailu.io/master/contributors/workflow.html#changelog) entry file.


Co-authored-by: Dimitri Huisman <diman@huisman.xyz>
main
bors[bot] 1 year ago committed by GitHub
commit 4a24bd9e24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -5,8 +5,7 @@ import logging as log
import sys import sys
from socrate import system, conf from socrate import system, conf
system.set_env() args = system.set_env()
args = os.environ.copy()
log.basicConfig(stream=sys.stderr, level=args.get("LOG_LEVEL", "WARNING")) log.basicConfig(stream=sys.stderr, level=args.get("LOG_LEVEL", "WARNING"))
args['TLS_PERMISSIVE'] = str(args.get('TLS_PERMISSIVE')).lower() not in ('false', 'no') args['TLS_PERMISSIVE'] = str(args.get('TLS_PERMISSIVE')).lower() not in ('false', 'no')
@ -18,8 +17,8 @@ with open("/etc/resolv.conf") as handle:
args["RESOLVER"] = f"[{resolver}]" if ":" in resolver else resolver args["RESOLVER"] = f"[{resolver}]" if ":" in resolver else resolver
# TLS configuration # TLS configuration
cert_name = os.getenv("TLS_CERT_FILENAME", default="cert.pem") cert_name = args.get("TLS_CERT_FILENAME", "cert.pem")
keypair_name = os.getenv("TLS_KEYPAIR_FILENAME", default="key.pem") keypair_name = args.get("TLS_KEYPAIR_FILENAME", "key.pem")
args["TLS"] = { args["TLS"] = {
"cert": ("/certs/%s" % cert_name, "/certs/%s" % keypair_name), "cert": ("/certs/%s" % cert_name, "/certs/%s" % keypair_name),
"letsencrypt": ("/certs/letsencrypt/live/mailu/nginx-chain.pem", "letsencrypt": ("/certs/letsencrypt/live/mailu/nginx-chain.pem",
@ -37,7 +36,7 @@ def format_for_nginx(fullchain, output):
split = '-----END CERTIFICATE-----\n' split = '-----END CERTIFICATE-----\n'
with open(fullchain, 'r') as pem: with open(fullchain, 'r') as pem:
certs = [f'{cert}{split}' for cert in pem.read().split(split) if cert] certs = [f'{cert}{split}' for cert in pem.read().split(split) if cert]
if len(certs)>2 and os.getenv('LETSENCRYPT_SHORTCHAIN'): if len(certs)>2 and args.get('LETSENCRYPT_SHORTCHAIN'):
del certs[-1] del certs[-1]
with open(output, 'w') as pem: with open(output, 'w') as pem:
pem.write(''.join(certs)) pem.write(''.join(certs))

@ -70,14 +70,14 @@ Then on your own frontend, point to these local ports. In practice, you only nee
REAL_IP_FROM=x.x.x.x,y.y.y.y.y REAL_IP_FROM=x.x.x.x,y.y.y.y.y
#x.x.x.x,y.y.y.y.y is the static IP address your reverse proxy uses for connecting to Mailu. #x.x.x.x,y.y.y.y.y is the static IP address your reverse proxy uses for connecting to Mailu.
Because the admin interface is served as ``/admin``, the Webmail as ``/webmail``, the single sign on page as ``/sso``, webdav as ``/webdav``, the client-autoconfiguration and the static files endpoint as ``/static``, you may also want to use a single virtual host and serve other applications (still Nginx): Because the admin interface is served as ``/admin``, the RESTful API as ``/api``, the Webmail as ``/webmail``, the single sign on page as ``/sso``, webdav as ``/webdav``, the client-autoconfiguration and the static files endpoint as ``/static``, you may also want to use a single virtual host and serve other applications (still Nginx):
.. code-block:: nginx .. code-block:: nginx
server { server {
# [...] here goes your standard configuration # [...] here goes your standard configuration
location ~* ^/(admin|sso|static|webdav|webmail|(apple\.)?mobileconfig|(\.well\-known/autoconfig/)?mail/|Autodiscover/Autodiscover) { location ~* ^/(admin|api|sso|static|webdav|webmail|(apple\.)?mobileconfig|(\.well\-known/autoconfig/)?mail/|Autodiscover/Autodiscover) {
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_pass https://localhost:8443; proxy_pass https://localhost:8443;

@ -1,12 +1,5 @@
//API_TOKEN generator //Store API token in variable.
var chars = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ"; var token = $("#api_token").val();
var tokenLength = 12;
var token = "";
for (var i = 0; i <= tokenLength; i++) {
var randomNumber = Math.floor(Math.random() * chars.length);
token += chars.substring(randomNumber, randomNumber +1);
}
$(document).ready(function() { $(document).ready(function() {
if ($("#webmail").val() == 'none') { if ($("#webmail").val() == 'none') {
@ -44,7 +37,7 @@ $(document).ready(function() {
}); });
$(document).ready(function() { $(document).ready(function() {
if ($('#api').prop('checked')) { if ($('#api_enabled').prop('checked')) {
$("#api_path").show(); $("#api_path").show();
$("#api_path").val("/api") $("#api_path").val("/api")
$("#api_token").show(); $("#api_token").show();
@ -53,13 +46,13 @@ $(document).ready(function() {
$("#api_token_label").show(); $("#api_token_label").show();
} else { } else {
$("#api_path").hide(); $("#api_path").hide();
$("#api_path").val("/api") $("#api_path").val("")
$("#api_token").hide(); $("#api_token").hide();
$("#api_token").prop('required',false); $("#api_token").prop('required',false);
$("#api_token").val(""); $("#api_token").val("");
$("#api_token_label").hide(); $("#api_token_label").hide();
} }
$("#api").change(function() { $("#api_enabled").change(function() {
if ($(this).is(":checked")) { if ($(this).is(":checked")) {
$("#api_path").show(); $("#api_path").show();
$("#api_path").val("/api"); $("#api_path").val("/api");
@ -69,7 +62,7 @@ $(document).ready(function() {
$("#api_token_label").show(); $("#api_token_label").show();
} else { } else {
$("#api_path").hide(); $("#api_path").hide();
$("#api_path").val("/api") $("#api_path").val("")
$("#api_token").hide(); $("#api_token").hide();
$("#api_token").prop('required',false); $("#api_token").prop('required',false);
$("#api_token").val(""); $("#api_token").val("");

@ -93,11 +93,11 @@ manage your email domains, users, etc.</p>
It is not possible to use the API without an API token.</p> It is not possible to use the API without an API token.</p>
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="api_enabled" value="false" id="api" > <input type="checkbox" name="api_enabled" value="true" id="api_enabled" >
<label>Enable the API (and path to the API)</label> <label>Enable the API (and path to the API)</label>
<input class="form-control" type="text" name="api_path" id="api_path" style="display: none"> <input class="form-control" type="text" name="api_path" id="api_path" style="display: none">
<label name="api_token_label" id="api_token_label">API token</label> <label name="api_token_label" id="api_token_label">API token</label>
<input class="form-control" type="text" name="api_token" id="api_token" style="display: none"> <input class="form-control" type="text" name="api_token" id="api_token" style="display: none" value="{{ secret(32) }}">
</div> </div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

Loading…
Cancel
Save