mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2025-04-20 02:52:11 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
114fc4fbec
11
CHANGELOG.md
11
CHANGELOG.md
@ -1,6 +1,17 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
In Development
|
||||||
|
--------------
|
||||||
|
|
||||||
|
* Incoming emails with SPF/DKIM/DMARC failures now have a higher spam score, and these messages are more likely to appear in the junk folder, since they are often spam/phishing.
|
||||||
|
* A new Download button in the control panel's External DNS page can be used to download the required DNS records in zonefile format.
|
||||||
|
* Backblaze B2 is now a supported backup protocol.
|
||||||
|
* Fixed the problem when the control panel would report DNS entries as Not Set by increasing a bind query limit.
|
||||||
|
* Fixed a control panel startup bug on some systems.
|
||||||
|
* Fixed the MTA-STS policy file's line endings.
|
||||||
|
* Nextcloud's photos, dashboard, and activity apps are disabled since we only support contacts and calendar.
|
||||||
|
|
||||||
v0.51 (November 14, 2020)
|
v0.51 (November 14, 2020)
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ info:
|
|||||||
license:
|
license:
|
||||||
name: CC0 1.0 Universal
|
name: CC0 1.0 Universal
|
||||||
url: https://creativecommons.org/publicdomain/zero/1.0/legalcode
|
url: https://creativecommons.org/publicdomain/zero/1.0/legalcode
|
||||||
version: 0.47.0
|
version: 0.51.0
|
||||||
x-logo:
|
x-logo:
|
||||||
url: https://mailinabox.email/static/logo.png
|
url: https://mailinabox.email/static/logo.png
|
||||||
altText: Mail-in-a-Box logo
|
altText: Mail-in-a-Box logo
|
||||||
@ -743,6 +743,38 @@ paths:
|
|||||||
text/html:
|
text/html:
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
/dns/zonefile/{zone}:
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: zone
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Hostname'
|
||||||
|
required: true
|
||||||
|
description: Hostname
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- DNS
|
||||||
|
summary: Get DNS zonefile
|
||||||
|
description: Returns a DNS zone file for a hostname.
|
||||||
|
operationId: getDnsZonefile
|
||||||
|
x-codeSamples:
|
||||||
|
- lang: curl
|
||||||
|
source: |
|
||||||
|
curl -X GET "https://{host}/admin/dns/zonefile/<zone>" \
|
||||||
|
-u "<email>:<password>"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: Successful operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DNSZonefileResponse'
|
||||||
|
403:
|
||||||
|
description: Forbidden
|
||||||
|
content:
|
||||||
|
text/html:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
/dns/update:
|
/dns/update:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@ -1781,7 +1813,7 @@ components:
|
|||||||
text/plain:
|
text/plain:
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
example: 1.2.3.4
|
example: '1.2.3.4'
|
||||||
description: The value of the DNS record.
|
description: The value of the DNS record.
|
||||||
example: '1.2.3.4'
|
example: '1.2.3.4'
|
||||||
schemas:
|
schemas:
|
||||||
@ -2050,6 +2082,8 @@ components:
|
|||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/Hostname'
|
$ref: '#/components/schemas/Hostname'
|
||||||
description: DNS zones response.
|
description: DNS zones response.
|
||||||
|
DNSZonefileResponse:
|
||||||
|
type: string
|
||||||
DNSSecondaryNameserverResponse:
|
DNSSecondaryNameserverResponse:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
@ -2663,13 +2697,6 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
MfaEnableSuccessResponse:
|
MfaEnableSuccessResponse:
|
||||||
type: string
|
type: string
|
||||||
MfaEnableBadRequestResponse:
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- error
|
|
||||||
properties:
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
MfaDisableRequest:
|
MfaDisableRequest:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -456,6 +456,23 @@ def list_target_files(config):
|
|||||||
raise ValueError(e.reason)
|
raise ValueError(e.reason)
|
||||||
|
|
||||||
return [(key.name[len(path):], key.size) for key in bucket.list(prefix=path)]
|
return [(key.name[len(path):], key.size) for key in bucket.list(prefix=path)]
|
||||||
|
elif target.scheme == 'b2':
|
||||||
|
from b2sdk.v1 import InMemoryAccountInfo, B2Api
|
||||||
|
from b2sdk.v1.exception import NonExistentBucket
|
||||||
|
info = InMemoryAccountInfo()
|
||||||
|
b2_api = B2Api(info)
|
||||||
|
|
||||||
|
# Extract information from target
|
||||||
|
b2_application_keyid = target.netloc[:target.netloc.index(':')]
|
||||||
|
b2_application_key = target.netloc[target.netloc.index(':')+1:target.netloc.index('@')]
|
||||||
|
b2_bucket = target.netloc[target.netloc.index('@')+1:]
|
||||||
|
|
||||||
|
try:
|
||||||
|
b2_api.authorize_account("production", b2_application_keyid, b2_application_key)
|
||||||
|
bucket = b2_api.get_bucket_by_name(b2_bucket)
|
||||||
|
except NonExistentBucket as e:
|
||||||
|
raise ValueError("B2 Bucket does not exist. Please double check your information!")
|
||||||
|
return [(key.file_name, key.size) for key, _ in bucket.ls()]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValueError(config["target"])
|
raise ValueError(config["target"])
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
#!/usr/local/lib/mailinabox/env/bin/python3
|
||||||
|
#
|
||||||
|
# During development, you can start the Mail-in-a-Box control panel
|
||||||
|
# by running this script, e.g.:
|
||||||
|
#
|
||||||
|
# service mailinabox stop # stop the system process
|
||||||
|
# DEBUG=1 management/daemon.py
|
||||||
|
# service mailinabox start # when done debugging, start it up again
|
||||||
|
|
||||||
import os, os.path, re, json, time
|
import os, os.path, re, json, time
|
||||||
import multiprocessing.pool, subprocess
|
import multiprocessing.pool, subprocess
|
||||||
|
|
||||||
@ -338,6 +347,12 @@ def dns_get_dump():
|
|||||||
from dns_update import build_recommended_dns
|
from dns_update import build_recommended_dns
|
||||||
return json_response(build_recommended_dns(env))
|
return json_response(build_recommended_dns(env))
|
||||||
|
|
||||||
|
@app.route('/dns/zonefile/<zone>')
|
||||||
|
@authorized_personnel_only
|
||||||
|
def dns_get_zonefile(zone):
|
||||||
|
from dns_update import get_dns_zonefile
|
||||||
|
return Response(get_dns_zonefile(zone, env), status=200, mimetype='text/plain')
|
||||||
|
|
||||||
# SSL
|
# SSL
|
||||||
|
|
||||||
@app.route('/ssl/status')
|
@app.route('/ssl/status')
|
||||||
@ -672,7 +687,22 @@ def log_failed_login(request):
|
|||||||
# APP
|
# APP
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if "DEBUG" in os.environ: app.debug = True
|
if "DEBUG" in os.environ:
|
||||||
|
# Turn on Flask debugging.
|
||||||
|
app.debug = True
|
||||||
|
|
||||||
|
# Use a stable-ish master API key so that login sessions don't restart on each run.
|
||||||
|
# Use /etc/machine-id to seed the key with a stable secret, but add something
|
||||||
|
# and hash it to prevent possibly exposing the machine id, using the time so that
|
||||||
|
# the key is not valid indefinitely.
|
||||||
|
import hashlib
|
||||||
|
with open("/etc/machine-id") as f:
|
||||||
|
api_key = f.read()
|
||||||
|
api_key += "|" + str(int(time.time() / (60*60*2)))
|
||||||
|
hasher = hashlib.sha1()
|
||||||
|
hasher.update(api_key.encode("ascii"))
|
||||||
|
auth_service.key = hasher.hexdigest()
|
||||||
|
|
||||||
if "APIKEY" in os.environ: auth_service.key = os.environ["APIKEY"]
|
if "APIKEY" in os.environ: auth_service.key = os.environ["APIKEY"]
|
||||||
|
|
||||||
if not app.debug:
|
if not app.debug:
|
||||||
|
@ -470,14 +470,14 @@ def write_nsd_zone(domain, zonefile, records, env, force):
|
|||||||
|
|
||||||
zone = """
|
zone = """
|
||||||
$ORIGIN {domain}.
|
$ORIGIN {domain}.
|
||||||
$TTL 1800 ; default time to live
|
$TTL 86400 ; default time to live
|
||||||
|
|
||||||
@ IN SOA ns1.{primary_domain}. hostmaster.{primary_domain}. (
|
@ IN SOA ns1.{primary_domain}. hostmaster.{primary_domain}. (
|
||||||
__SERIAL__ ; serial number
|
__SERIAL__ ; serial number
|
||||||
7200 ; Refresh (secondary nameserver update interval)
|
7200 ; Refresh (secondary nameserver update interval)
|
||||||
1800 ; Retry (when refresh fails, how often to try again)
|
86400 ; Retry (when refresh fails, how often to try again)
|
||||||
1209600 ; Expire (when refresh fails, how long secondary nameserver will keep records around anyway)
|
1209600 ; Expire (when refresh fails, how long secondary nameserver will keep records around anyway)
|
||||||
1800 ; Negative TTL (how long negative responses are cached)
|
86400 ; Negative TTL (how long negative responses are cached)
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -564,6 +564,17 @@ $TTL 1800 ; default time to live
|
|||||||
|
|
||||||
return True # file is updated
|
return True # file is updated
|
||||||
|
|
||||||
|
def get_dns_zonefile(zone, env):
|
||||||
|
for domain, fn in get_dns_zones(env):
|
||||||
|
if zone == domain:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError("%s is not a domain name that corresponds to a zone." % zone)
|
||||||
|
|
||||||
|
nsd_zonefile = "/etc/nsd/zones/" + fn
|
||||||
|
with open(nsd_zonefile, "r") as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
|
|
||||||
def write_nsd_conf(zonefiles, additional_records, env):
|
def write_nsd_conf(zonefiles, additional_records, env):
|
||||||
|
@ -42,6 +42,19 @@
|
|||||||
You may need to adopt this technique when adding DomainKeys. Use a tool like <code>named-checkzone</code> to validate your zone file.
|
You may need to adopt this technique when adding DomainKeys. Use a tool like <code>named-checkzone</code> to validate your zone file.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3>Download zonefile</h3>
|
||||||
|
<p>You can download your zonefiles here or use the table of records below.</p>
|
||||||
|
<form class="form-inline" role="form" onsubmit="do_download_zonefile(); return false;">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="downloadZonefile" class="control-label sr-only">Zone</label>
|
||||||
|
<select id="downloadZonefile" class="form-control" style="width: auto"> </select>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Download</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<h3>Records</h3>
|
||||||
|
|
||||||
<table id="external_dns_settings" class="table">
|
<table id="external_dns_settings" class="table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -57,6 +70,18 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
function show_external_dns() {
|
function show_external_dns() {
|
||||||
|
api(
|
||||||
|
"/dns/zones",
|
||||||
|
"GET",
|
||||||
|
{ },
|
||||||
|
function(data) {
|
||||||
|
var zones = $('#downloadZonefile');
|
||||||
|
zones.text('');
|
||||||
|
for (var j = 0; j < data.length; j++) {
|
||||||
|
zones.append($('<option/>').text(data[j]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$('#external_dns_settings tbody').html("<tr><td colspan='2' class='text-muted'>Loading...</td></tr>")
|
$('#external_dns_settings tbody').html("<tr><td colspan='2' class='text-muted'>Loading...</td></tr>")
|
||||||
api(
|
api(
|
||||||
"/dns/dump",
|
"/dns/dump",
|
||||||
@ -84,4 +109,19 @@ function show_external_dns() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function do_download_zonefile() {
|
||||||
|
var zone = $('#downloadZonefile').val();
|
||||||
|
|
||||||
|
api(
|
||||||
|
"/dns/zonefile/"+ zone,
|
||||||
|
"GET",
|
||||||
|
{},
|
||||||
|
function(data) {
|
||||||
|
show_modal_error("Download Zonefile", $("<pre/>").text(data));
|
||||||
|
},
|
||||||
|
function(err) {
|
||||||
|
show_modal_error("Download Zonefile (Error)", $("<pre/>").text(err));
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
<option value="local">{{hostname}}</option>
|
<option value="local">{{hostname}}</option>
|
||||||
<option value="rsync">rsync</option>
|
<option value="rsync">rsync</option>
|
||||||
<option value="s3">Amazon S3</option>
|
<option value="s3">Amazon S3</option>
|
||||||
|
<option value="b2">Backblaze B2</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -111,6 +112,31 @@
|
|||||||
<input type="text" class="form-control" rows="1" id="backup-target-pass">
|
<input type="text" class="form-control" rows="1" id="backup-target-pass">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Backblaze -->
|
||||||
|
<div class="form-group backup-target-b2">
|
||||||
|
<div class="col-sm-10 col-sm-offset-2">
|
||||||
|
<p>Backups are stored in a <a href="https://www.backblaze.com/" target="_blank" rel="noreferrer">Backblaze</a> B2 bucket. You must have a Backblaze account already.</p>
|
||||||
|
<p>You MUST manually copy the encryption password from <tt class="backup-encpassword-file"></tt> to a safe and secure location. You will need this file to decrypt backup files. It is NOT stored in your Backblaze B2 bucket.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group backup-target-b2">
|
||||||
|
<label for="backup-target-b2-user" class="col-sm-2 control-label">B2 Application KeyID</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="text" class="form-control" rows="1" id="backup-target-b2-user">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group backup-target-b2">
|
||||||
|
<label for="backup-target-b2-pass" class="col-sm-2 control-label">B2 Application Key</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="text" class="form-control" rows="1" id="backup-target-b2-pass">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group backup-target-b2">
|
||||||
|
<label for="backup-target-b2-bucket" class="col-sm-2 control-label">B2 Bucket</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="text" class="form-control" rows="1" id="backup-target-b2-bucket">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Common -->
|
<!-- Common -->
|
||||||
<div class="form-group backup-target-local backup-target-rsync backup-target-s3">
|
<div class="form-group backup-target-local backup-target-rsync backup-target-s3">
|
||||||
<label for="min-age" class="col-sm-2 control-label">Retention Days:</label>
|
<label for="min-age" class="col-sm-2 control-label">Retention Days:</label>
|
||||||
@ -144,7 +170,7 @@
|
|||||||
|
|
||||||
function toggle_form() {
|
function toggle_form() {
|
||||||
var target_type = $("#backup-target-type").val();
|
var target_type = $("#backup-target-type").val();
|
||||||
$(".backup-target-local, .backup-target-rsync, .backup-target-s3").hide();
|
$(".backup-target-local, .backup-target-rsync, .backup-target-s3, .backup-target-b2").hide();
|
||||||
$(".backup-target-" + target_type).show();
|
$(".backup-target-" + target_type).show();
|
||||||
|
|
||||||
init_inputs(target_type);
|
init_inputs(target_type);
|
||||||
@ -215,7 +241,7 @@ function show_system_backup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function show_custom_backup() {
|
function show_custom_backup() {
|
||||||
$(".backup-target-local, .backup-target-rsync, .backup-target-s3").hide();
|
$(".backup-target-local, .backup-target-rsync, .backup-target-s3, .backup-target-b2").hide();
|
||||||
api(
|
api(
|
||||||
"/system/backup/config",
|
"/system/backup/config",
|
||||||
"GET",
|
"GET",
|
||||||
@ -245,6 +271,15 @@ function show_custom_backup() {
|
|||||||
var host = hostpath.shift();
|
var host = hostpath.shift();
|
||||||
$("#backup-target-s3-host").val(host);
|
$("#backup-target-s3-host").val(host);
|
||||||
$("#backup-target-s3-path").val(hostpath.join('/'));
|
$("#backup-target-s3-path").val(hostpath.join('/'));
|
||||||
|
} else if (r.target.substring(0, 5) == "b2://") {
|
||||||
|
$("#backup-target-type").val("b2");
|
||||||
|
var targetPath = r.target.substring(5);
|
||||||
|
var b2_application_keyid = targetPath.split(':')[0];
|
||||||
|
var b2_applicationkey = targetPath.split(':')[1].split('@')[0];
|
||||||
|
var b2_bucket = targetPath.split('@')[1];
|
||||||
|
$("#backup-target-b2-user").val(b2_application_keyid);
|
||||||
|
$("#backup-target-b2-pass").val(b2_applicationkey);
|
||||||
|
$("#backup-target-b2-bucket").val(b2_bucket);
|
||||||
}
|
}
|
||||||
toggle_form()
|
toggle_form()
|
||||||
})
|
})
|
||||||
@ -264,6 +299,11 @@ function set_custom_backup() {
|
|||||||
target = "rsync://" + $("#backup-target-rsync-user").val() + "@" + $("#backup-target-rsync-host").val()
|
target = "rsync://" + $("#backup-target-rsync-user").val() + "@" + $("#backup-target-rsync-host").val()
|
||||||
+ "/" + $("#backup-target-rsync-path").val();
|
+ "/" + $("#backup-target-rsync-path").val();
|
||||||
target_user = '';
|
target_user = '';
|
||||||
|
} else if (target_type == "b2") {
|
||||||
|
target = 'b2://' + $('#backup-target-b2-user').val() + ':' + $('#backup-target-b2-pass').val()
|
||||||
|
+ '@' + $('#backup-target-b2-bucket').val()
|
||||||
|
target_user = '';
|
||||||
|
target_pass = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
<button type="submit" class="btn btn-primary">Add User</button>
|
<button type="submit" class="btn btn-primary">Add User</button>
|
||||||
</form>
|
</form>
|
||||||
<ul style="margin-top: 1em; padding-left: 1.5em; font-size: 90%;">
|
<ul style="margin-top: 1em; padding-left: 1.5em; font-size: 90%;">
|
||||||
<li>Passwords must be at least eight characters consisting of English lettters and numbers only. For best results, <a href="#" onclick="return generate_random_password()">generate a random password</a>.</li>
|
<li>Passwords must be at least eight characters consisting of English letters and numbers only. For best results, <a href="#" onclick="return generate_random_password()">generate a random password</a>.</li>
|
||||||
<li>Use <a href="#" onclick="return show_panel('aliases')">aliases</a> to create email addresses that forward to existing accounts.</li>
|
<li>Use <a href="#" onclick="return show_panel('aliases')">aliases</a> to create email addresses that forward to existing accounts.</li>
|
||||||
<li>Administrators get access to this control panel.</li>
|
<li>Administrators get access to this control panel.</li>
|
||||||
<li>User accounts cannot contain any international (non-ASCII) characters, but <a href="#" onclick="return show_panel('aliases');">aliases</a> can.</li>
|
<li>User accounts cannot contain any international (non-ASCII) characters, but <a href="#" onclick="return show_panel('aliases');">aliases</a> can.</li>
|
||||||
|
@ -18,11 +18,7 @@ while [ -d /usr/local/lib/python3.4/dist-packages/acme ]; do
|
|||||||
pip3 uninstall -y acme;
|
pip3 uninstall -y acme;
|
||||||
done
|
done
|
||||||
|
|
||||||
# duplicity is used to make backups of user data. It uses boto
|
# duplicity is used to make backups of user data.
|
||||||
# (via Python 2) to do backups to AWS S3. boto from the Ubuntu
|
|
||||||
# package manager is too out-of-date -- it doesn't support the newer
|
|
||||||
# S3 api used in some regions, which breaks backups to those regions.
|
|
||||||
# See #627, #653.
|
|
||||||
#
|
#
|
||||||
# virtualenv is used to isolate the Python 3 packages we
|
# virtualenv is used to isolate the Python 3 packages we
|
||||||
# install via pip from the system-installed packages.
|
# install via pip from the system-installed packages.
|
||||||
@ -30,7 +26,11 @@ done
|
|||||||
# certbot installs EFF's certbot which we use to
|
# certbot installs EFF's certbot which we use to
|
||||||
# provision free TLS certificates.
|
# provision free TLS certificates.
|
||||||
apt_install duplicity python-pip virtualenv certbot
|
apt_install duplicity python-pip virtualenv certbot
|
||||||
hide_output pip2 install --upgrade boto
|
|
||||||
|
# b2sdk is used for backblaze backups.
|
||||||
|
# boto is used for amazon aws backups.
|
||||||
|
# Both are installed outside the pipenv, so they can be used by duplicity
|
||||||
|
hide_output pip3 install --upgrade b2sdk boto
|
||||||
|
|
||||||
# Create a virtualenv for the installation of Python 3 packages
|
# Create a virtualenv for the installation of Python 3 packages
|
||||||
# used by the management daemon.
|
# used by the management daemon.
|
||||||
@ -51,7 +51,7 @@ hide_output $venv/bin/pip install --upgrade \
|
|||||||
rtyaml "email_validator>=1.0.0" "exclusiveprocess" \
|
rtyaml "email_validator>=1.0.0" "exclusiveprocess" \
|
||||||
flask dnspython python-dateutil \
|
flask dnspython python-dateutil \
|
||||||
qrcode[pil] pyotp \
|
qrcode[pil] pyotp \
|
||||||
"idna>=2.0.0" "cryptography==2.2.2" boto psutil postfix-mta-sts-resolver
|
"idna>=2.0.0" "cryptography==2.2.2" boto psutil postfix-mta-sts-resolver b2sdk
|
||||||
|
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
|
|
||||||
@ -90,6 +90,12 @@ rm -f /tmp/bootstrap.zip
|
|||||||
# running after a reboot.
|
# running after a reboot.
|
||||||
cat > $inst_dir/start <<EOF;
|
cat > $inst_dir/start <<EOF;
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# Set character encoding flags to ensure that any non-ASCII don't cause problems.
|
||||||
|
export LANGUAGE=en_US.UTF-8
|
||||||
|
export LC_ALL=en_US.UTF-8
|
||||||
|
export LANG=en_US.UTF-8
|
||||||
|
export LC_TYPE=en_US.UTF-8
|
||||||
|
|
||||||
source $venv/bin/activate
|
source $venv/bin/activate
|
||||||
exec python `pwd`/management/daemon.py
|
exec python `pwd`/management/daemon.py
|
||||||
EOF
|
EOF
|
||||||
|
@ -93,6 +93,9 @@ hide_output add-apt-repository -y universe
|
|||||||
# Install the certbot PPA.
|
# Install the certbot PPA.
|
||||||
hide_output add-apt-repository -y ppa:certbot/certbot
|
hide_output add-apt-repository -y ppa:certbot/certbot
|
||||||
|
|
||||||
|
# Install the duplicity PPA.
|
||||||
|
hide_output add-apt-repository -y ppa:duplicity-team/duplicity-release-git
|
||||||
|
|
||||||
# ### Update Packages
|
# ### Update Packages
|
||||||
|
|
||||||
# Update system packages to make sure we have the latest upstream versions
|
# Update system packages to make sure we have the latest upstream versions
|
||||||
@ -317,6 +320,9 @@ fi #NODOC
|
|||||||
# name server, on IPV6.
|
# name server, on IPV6.
|
||||||
# * The listen-on directive in named.conf.options restricts `bind9` to
|
# * The listen-on directive in named.conf.options restricts `bind9` to
|
||||||
# binding to the loopback interface instead of all interfaces.
|
# binding to the loopback interface instead of all interfaces.
|
||||||
|
# * The max-recursion-queries directive increases the maximum number of iterative queries.
|
||||||
|
# If more queries than specified are sent, bind9 returns SERVFAIL. After flushing the cache during system checks,
|
||||||
|
# we ran into the limit thus we are increasing it from 75 (default value) to 100.
|
||||||
apt_install bind9
|
apt_install bind9
|
||||||
tools/editconf.py /etc/default/bind9 \
|
tools/editconf.py /etc/default/bind9 \
|
||||||
"OPTIONS=\"-u bind -4\""
|
"OPTIONS=\"-u bind -4\""
|
||||||
@ -324,6 +330,10 @@ if ! grep -q "listen-on " /etc/bind/named.conf.options; then
|
|||||||
# Add a listen-on directive if it doesn't exist inside the options block.
|
# Add a listen-on directive if it doesn't exist inside the options block.
|
||||||
sed -i "s/^}/\n\tlisten-on { 127.0.0.1; };\n}/" /etc/bind/named.conf.options
|
sed -i "s/^}/\n\tlisten-on { 127.0.0.1; };\n}/" /etc/bind/named.conf.options
|
||||||
fi
|
fi
|
||||||
|
if ! grep -q "max-recursion-queries " /etc/bind/named.conf.options; then
|
||||||
|
# Add a max-recursion-queries directive if it doesn't exist inside the options block.
|
||||||
|
sed -i "s/^}/\n\tmax-recursion-queries 100;\n}/" /etc/bind/named.conf.options
|
||||||
|
fi
|
||||||
|
|
||||||
# First we'll disable systemd-resolved's management of resolv.conf and its stub server.
|
# First we'll disable systemd-resolved's management of resolv.conf and its stub server.
|
||||||
# Breaking the symlink to /run/systemd/resolve/stub-resolv.conf means
|
# Breaking the symlink to /run/systemd/resolve/stub-resolv.conf means
|
||||||
|
@ -28,8 +28,8 @@ apt_install \
|
|||||||
# Install Roundcube from source if it is not already present or if it is out of date.
|
# Install Roundcube from source if it is not already present or if it is out of date.
|
||||||
# Combine the Roundcube version number with the commit hash of plugins to track
|
# Combine the Roundcube version number with the commit hash of plugins to track
|
||||||
# whether we have the latest version of everything.
|
# whether we have the latest version of everything.
|
||||||
VERSION=1.4.9
|
VERSION=1.4.10
|
||||||
HASH=df650f4d3eae9eaae2d5a5f06d68665691daf57d
|
HASH=36b2351030e1ebddb8e39190d7b0ba82b1bbec1b
|
||||||
PERSISTENT_LOGIN_VERSION=6b3fc450cae23ccb2f393d0ef67aa319e877e435
|
PERSISTENT_LOGIN_VERSION=6b3fc450cae23ccb2f393d0ef67aa319e877e435
|
||||||
HTML5_NOTIFIER_VERSION=4b370e3cd60dabd2f428a26f45b677ad1b7118d5
|
HTML5_NOTIFIER_VERSION=4b370e3cd60dabd2f428a26f45b677ad1b7118d5
|
||||||
CARDDAV_VERSION=3.0.3
|
CARDDAV_VERSION=3.0.3
|
||||||
|
Loading…
Reference in New Issue
Block a user