Compare commits

...

121 commits
v1.1 ... master

Author SHA1 Message Date
Tuxis B.V.
7a18c00a24
Merge pull request #206 from bartvanhalder/master
Add support to load templates from json files
2025-03-11 09:17:49 +01:00
Tuxis B.V.
2ea8bff800
Merge pull request #207 from PowerDNS/docker-bookworm
update Dockerfile to Debian bookworm
2025-03-11 09:16:24 +01:00
Peter van Dijk
12d3d33c36 update Dockerfile to Debian bookworm 2025-03-10 15:20:29 +01:00
Tuxis B.V.
6c565719d9
Merge pull request #189 from stecklars/master
INCEPTION-INCREMENT is not a valid option for soa_edit_api
2024-08-19 14:41:51 +02:00
Tuxis B.V.
fe4120e2a7
Merge pull request #205 from deividasraila/feat/default_login_credentials
Default login crediantials in config
2024-08-19 14:40:55 +02:00
Bart van Halder
8e1d0035d3
[.gitignore] ignore json files in templates.d/ 2024-07-25 15:38:00 +02:00
Bart van Halder
a3ba9ed45e
Add a way to load templates from json files 2024-07-25 15:32:03 +02:00
Deividas Raila
3b69fcf770 Default login crediantials in config 2024-05-07 18:11:07 +03:00
Tuxis B.V
65d58cfd92
Merge pull request #204 from WilliamDEdwards/fix/ipv6-api-ip
Place brackets around IPv6 address
2024-04-29 21:39:17 +02:00
William Edwards
c8f28c5c3e Place brackets around IPv6 address
Without this, using an IPv6 address as $apiip is not possible, because cURL requires brackets.
2024-04-29 20:48:04 +02:00
Tuxis B.V
39050cd015
Merge pull request #203 from WilliamDEdwards/fix/make-clone-admin-only
Make cloning admin-only, check zones returned by formzonelist
2024-04-17 12:21:46 +02:00
William Edwards
e8d028ba75 Make cloning admin-only, check zones returned by formzonelist
Cloning was meant to be an admin-only functionality. However, this was not fully implemented: when `allowzoneadd = true`, the user could clone zones, even when not an admin. This is not necessarily a problem. But in this case, it is. Because the endpoint that is used to get zones to clone (`formzonelist`), did not check whether those zones belong to the current user. In other words: when `allowzoneadd = true` and the user is not an admin, that user is able to see *all zones* under 'Clone a zone' button -> 'Source domain' dropdown.

This commit fixes that, by letting `formzonelist` return only zones belonging to the user, and showing the 'Clone a zone' button only when the user is an admin.
2024-04-17 12:18:06 +02:00
Tuxis B.V
a4aa3c35cf
Merge pull request #202 from WilliamDEdwards/fix/add-missing-return
Add missing return to Comment::export
2024-01-23 17:13:29 +01:00
William Edwards
e5a121f24b Add missing return to Comment::export
Without this return, RRSet::exportComments returns an array of `null`, which causes PowerDNS to return `Key 'content' not present or not a String`.
2024-01-23 16:21:18 +01:00
Tuxis B.V
76d70251bb
Merge pull request #201 from zydronium/master
Deprecated: Creation of dynamic properties is deprecated in PHP8.2
2023-06-20 15:46:30 +02:00
Jelle Luteijn
b7ef64db18
Update Zone.php 2023-06-20 14:24:17 +02:00
Jelle Luteijn
758a021ca2
Update Zone.php 2023-06-20 14:22:36 +02:00
Jelle Luteijn
cae4e4ff93
Update Zone.php 2023-06-20 14:14:45 +02:00
Jelle Luteijn
7c50964633
Update ApiHandler.php 2023-06-20 14:13:08 +02:00
Jelle Luteijn
d59da92f37
Update PdnsApi.php
Creation of dynamic property PdnsAPI::$http is deprecated
2023-06-20 14:12:30 +02:00
Jelle Luteijn
607ecbd9f2
forgot $ 2023-06-20 14:06:52 +02:00
Jelle Luteijn
c327e23859
Update session.inc.php
Passing null to parameter #2 ($value) of type string is deprecated
2023-06-20 14:03:20 +02:00
Jelle Luteijn
e38fa1e120
Update ApiHandler.php
Creation of dynamic property ApiHandler::$headers is deprecated
2023-06-20 13:57:08 +02:00
Jelle Luteijn
b8e3261180
Update session.inc.php
Using ${var} in strings is deprecated, use {$var} instead
2023-06-20 13:45:10 +02:00
Tuxis B.V
947ec4a67d
Merge pull request #195 from tuxis-ie/check-authdb-docroot
Simply check if authdb is in the docroot.
2020-12-23 13:14:48 +01:00
Mark Schouten
d414f239a8 Simply check if authdb is in the docroot. If so, just blocklogin with a nice message. 2020-12-23 13:11:40 +01:00
Tuxis B.V
8efcfbd597
Merge pull request #194 from tuxis-ie/template-ns-records
If a template contains NS-records, do not try to add them again. They were already added while creating the zone.
2020-12-23 11:48:42 +01:00
Mark Schouten
5c6c9e1847 If a template contains NS-records, do not try to add them again. They were already added while creating the zone. 2020-12-23 11:45:58 +01:00
Tuxis B.V
888e7bad42
Merge pull request #193 from margau/master
AuthDB Download Check improvements
2020-11-26 09:47:28 +01:00
Marvin Gaube
82db64595c authdb check: Use relative, not absolute path 2020-03-01 20:18:15 +01:00
Marvin Gaube
6ba23a85b8 Only run authdb check when user is logged in 2020-03-01 20:15:14 +01:00
Tuxis B.V
059c679193
Merge pull request #192 from jbrunemann/master
#188 only replace basename when there is actually something to replace
2020-01-22 11:43:33 +01:00
Jan Brunemann
8586816c47 #188 only replace basename when there is actually something to replace 2020-01-22 11:33:27 +01:00
Lars-Sören Steck
de278c9ad7
INCEPTION-INCREMENT is not a valid option for soa_edit_api
INCEPTION-INCREMENT is not a valid option for soa_edit_api, see:
https://doc.powerdns.com/authoritative/domainmetadata.html#soa-edit-api

-> "These rules are the same as the SOA-EDIT-DNSUPDATE rules."
--> https://doc.powerdns.com/authoritative/dnsupdate.html#dnsupdate-soa-serial-updates
---> There is no "INCEPTION-INCREMENT" Setting.

Since 4.2 this is more strictly checked by PowerDNS:
636301b9f1 (diff-fcc782f1cdc22f79be390c5d65da9050)

Before this, it would simply use the DEFAULT option, now it logs an error and doesn't increase the Serial.
2019-07-28 02:57:29 +02:00
Mark Schouten
371eb41787 Content must be canonical 2018-08-22 17:12:01 +02:00
Tuxis Internet Engineering V.O.F
c63dbba617
Merge pull request #183 from tuxis-ie/nice-authdb-error
Show a clear message instead of ERROR 500
2018-08-22 16:51:28 +02:00
Mark Schouten
9407c92a6a Show a clear message instead of ERROR 500 2018-08-22 16:51:07 +02:00
Tuxis Internet Engineering V.O.F
23b9fe2c54
Merge pull request #182 from tuxis-ie/margau-patch-1
Margau patch 1
2018-08-22 16:45:32 +02:00
Mark Schouten
523fc1849d Test if we can download the from the browser. Alert, annoyingly, that the user should fix this 2018-08-22 16:43:19 +02:00
Mark Schouten
3448ccf653 Merge branch 'patch-1' of https://github.com/margau/nsedit into margau-patch-1 2018-08-22 16:41:41 +02:00
Tuxis Internet Engineering V.O.F
e80aa0dca7
Merge pull request #181 from tuxis-ie/support-SMIMEA
Support SMIMEA fields, fixes and closes #174
2018-08-22 16:06:40 +02:00
Mark Schouten
92290bdf05 Support SMIMEA fields, fixes and closes #174 2018-08-22 16:05:48 +02:00
Tuxis Internet Engineering V.O.F
3facd3271f
Merge pull request #180 from tuxis-ie/fix-api-calls
Fix api calls
2018-08-22 15:54:32 +02:00
Mark Schouten
be647cc26a Do not insert 'localhost', we are autodetecting the API url 2018-08-22 15:39:11 +02:00
Mark Schouten
bf513b9ffd Assume that we have Pdns > 4.x 2018-08-22 15:21:26 +02:00
Tuxis Internet Engineering V.O.F
880508f585
Merge pull request #171 from margau/master
API issue with PDNS 4.1.1
2018-06-05 10:30:05 +02:00
margau
39cf7138ef
Update README.md 2018-04-17 19:41:33 +02:00
margau
e403e396bc
Update README.md 2018-04-17 19:37:38 +02:00
margau
96c67a8e8f
Added notice (see #172) 2018-04-17 19:33:58 +02:00
margau
805176648d Fixed from paulgiordanozethcon suggestion in https://github.com/tuxis-ie/nsedit/issues/162 2018-04-17 18:53:31 +02:00
Tuxis Internet Engineering V.O.F
ebd12ebeb2
Merge pull request #167 from zydronium/patch-1
Fixing Undefined index
2018-03-28 09:07:39 +02:00
Tuxis Internet Engineering V.O.F
1dedc3ae3f
Merge pull request #168 from hutchinsonnetworks/master
Docker: Move configuration to runtime rather than build time
2018-03-28 09:06:55 +02:00
Tuxis Internet Engineering V.O.F
77d7c50110
Merge pull request #169 from tuxis-ie/revert-166-master
Revert "notify pdns after zone update"
2018-03-28 09:05:28 +02:00
Tuxis Internet Engineering V.O.F
635441dbe0
Revert "notify pdns after zone update" 2018-03-28 09:05:09 +02:00
Tuxis Internet Engineering V.O.F
ed27b5e7d1
Merge pull request #166 from Rico29/master
notify pdns slaves after zone update
2018-03-28 09:03:11 +02:00
Harry Reeder
a2d7c21636 Move configuration to runtime rather than build time 2018-03-19 16:00:38 +00:00
Jelle Luteijn
4f013d4081
Fixing Undefined index
PHP Notice:  Undefined index: label in /var/www/nsedit/wwwroot/zones.php on line 325
2018-02-08 23:41:07 +01:00
root
d44b1a011f wrong syntax correction 2018-02-05 09:58:06 +01:00
root
6dc6df497e typo correction 2018-02-02 15:12:11 +01:00
root
cb234599b7 typo correction 2018-02-02 15:10:54 +01:00
root
03d9d88026 add "notifyafterupdate" flag 2018-02-02 14:58:10 +01:00
Tuxis Internet Engineering V.O.F
1dfd47ae70
Merge pull request #161 from tuxis-ie/fix-issue-160
Fix issue 160
2017-11-20 16:04:42 +01:00
Mark Schouten
c1c680217d Set zonekind of the new zone 2017-11-20 15:58:15 +01:00
Mark Schouten
374e03aa43 Add zone to database and fix ownership 2017-11-20 15:56:28 +01:00
Tuxis Internet Engineering V.O.F
877d433b92
Merge pull request #159 from jsoref/spelling
Spelling
2017-11-20 10:35:50 +01:00
Josh Soref
ac5304badb spelling: whether 2017-11-19 00:58:36 +00:00
Josh Soref
fd2a7cb7a5 spelling: nameserver 2017-11-17 09:23:49 +00:00
Josh Soref
c3bd9da355 spelling: configuration 2017-11-17 09:11:20 +00:00
Tuxis Internet Engineering V.O.F
0befe9e5ab Merge pull request #155 from maltris/master
Separated RUN-commands, changed a sed-command because the matching did not work
2017-10-05 11:29:53 +02:00
maltris
0c1183e716 Separated RUN-commands, changed a sed-command because the matching did not work 2017-08-14 10:22:04 +02:00
Tuxis Internet Engineering V.O.F
4b060c6430 Merge pull request #153 from webvanced/master
Added support for CNAME's to zone in templates
2017-08-07 10:32:40 +02:00
Mark Schouten
18fa97373e Add other ways of installation to the README 2017-08-07 10:30:52 +02:00
Daniel Eiland
1f2225cf6d Added support for CNAME's to zone in templates 2017-07-11 09:24:44 +02:00
Mark Schouten
382ca51db1 Allow ALIAS records. Closes #138 2017-04-28 13:37:22 +02:00
Mark Schouten
6be5f2f29c Fix updating the password, and store if we have local auth, we can't change passwords if we don't have local auth 2017-04-28 13:09:31 +02:00
Mark Schouten
f67fa04d85 This fixes the issues with the newer pdns, which suddenly includes the whole API url in the returned json.
Closes #145. In response to 4d4e536d52
2017-04-28 12:32:01 +02:00
Mark Schouten
9d27a140d7 Fix proto in logo url 2017-04-20 11:46:55 +02:00
Mark Schouten
4d4e536d52 Deduplicate the api-url 2017-04-20 11:45:33 +02:00
Tuxis Internet Engineering V.O.F
6fbd049941 Merge pull request #143 from tuxis-ie/caa-support
Implement CAA-records. Please note that pdns requires quotes around t…
2017-04-03 09:48:15 +02:00
Mark Schouten
0e63757d19 Implement CAA-records. Please note that pdns requires quotes around the third field: https://github.com/PowerDNS/pdns/issues/4937. Closes #141 2017-04-03 09:47:38 +02:00
Mark Schouten
5787659b07 Add this missing line, this may have broken editing of SPF/TXT records. Closes #140 2017-01-25 09:46:05 +01:00
Tuxis Internet Engineering V.O.F
b7d61f5778 Merge pull request #136 from krombel/master
fix switching of Views for non-admin-users (fix #135)
2016-11-21 10:15:03 +01:00
Krombel
a3affccacd fix switching of Views for non-admin-users (#135) 2016-11-19 02:50:09 +01:00
Mark Schouten
93c88cc196 If we get here, there is a value without dots... So add it 2016-11-18 17:11:22 +01:00
Mark Schouten
5c5f9f7abd Fix sorting 2016-11-18 17:07:49 +01:00
Mark Schouten
6737aa9b83 Fix matching on zonename, we were missing the . 2016-11-18 17:01:48 +01:00
Mark Schouten
ae00aa8ed9 Fix quoting of TXT and SPF records 2016-11-18 17:00:18 +01:00
Mark Schouten
42b247d5c0 Add missing types. Closes #130 2016-11-03 10:11:24 +01:00
Mark Schouten
41801a73f6 Try to set soa_edit_api, if it is not yet set 2016-10-25 12:14:07 +02:00
Mark Schouten
94e0d22bf2 If we don't have a soa_edit_api for this zone yet, set it to our default 2016-10-25 11:10:22 +02:00
Mark Schouten
77192d84b1 Don't close the database connection and make it global. Also, honour the account that is set in pdns, unless its empty 2016-10-19 17:28:16 +02:00
Mark Schouten
92ac4576ab An empty name is possible 2016-10-14 14:20:07 +02:00
Mark Schouten
b5d7fa8183 Don't forget the dot in between 2016-10-14 14:16:48 +02:00
Mark Schouten
83e8a0eda6 TRAILING DOTSS!!!11eleven!!11!&$W*&@*@!@#& 2016-10-14 14:14:17 +02:00
Mark Schouten
32f0456f21 Fix TXT-record quoting 2016-10-10 14:22:31 +02:00
Tuxis Internet Engineering V.O.F
b34d7ee2f1 Merge pull request #123 from richard-underwood/issue-122
Modified users jtable to use id & fixed user deletion.
2016-09-26 16:45:18 +02:00
Richard Underwood
083cb9429c Modified users jtable to use id & fixed user deletion. 2016-09-20 10:10:54 +01:00
Tuxis Internet Engineering V.O.F
e7713615a5 Merge pull request #120 from bjoe2k4/master 2016-09-19 12:04:51 +02:00
bjoe2k4
5d1f23c814 Update .gitignore 2016-09-17 15:27:29 +02:00
Tuxis Internet Engineering V.O.F
b16af25052 Merge pull request #108 from richard-underwood/issue-107
Ability to rotate and search logs
2016-09-13 11:10:22 +02:00
Richard Underwood
badebb9965 Clarified wording of rotation warning. 2016-08-26 11:59:49 +01:00
Richard Underwood
8d6e8ddf55 Removed delete button from logs table as the action wasn't implemented and would not be possible on rotated logs. 2016-08-26 11:45:30 +01:00
Richard Underwood
669c78a1db Merge remote-tracking branch 'origin/master' into issue-107 2016-08-26 10:54:04 +01:00
Tuxis Internet Engineering V.O.F
531f8a2609 Merge pull request #110 from richard-underwood/issue-109
PHP <= 5.4 fix for curl_reset
2016-08-26 11:50:48 +02:00
Richard Underwood
9d59441dd0 Check around curl_reset to prevent errors with PHP <=5.4 2016-08-26 10:11:52 +01:00
Richard Underwood
7c767b7769 Merge remote-tracking branch 'origin/master' into issue-107
Add test for pre-PHP 5.4 for pretty-printing logs

Conflicts:
	includes/misc.inc.php
2016-08-26 10:00:51 +01:00
Tuxis Internet Engineering V.O.F
6833f59400 Merge pull request #105 from tuxis-ie/fix-bug-104
Fix logging in cases we don't have a username yet. Also, log more stu…
2016-08-26 10:38:24 +02:00
Richard Underwood
2cb95a6959 UNRELATED CHANGE - put test around curl_reset to allow testing on PHP 5.4 2016-08-26 09:30:56 +01:00
Richard Underwood
befb891174 Changed Download logs to download the logs currently being shown, not always the current logs - note, doesn't filter first.
Removed "delete" case in logs.php
Moved logging check out of case statements to avoid duplication.
Changed wording of clear logs warning.
Pretty-print the JSON on log export - requires PHP 5.4.
2016-08-25 10:23:31 +01:00
Richard Underwood
ff8df5e5b2 Merge remote-tracking branch 'origin/master' into issue-107 2016-08-24 14:59:23 +01:00
Mark Schouten
43e4d53611 Fix CSS issues to eliminate whitespace with vertical menubar 2016-08-24 15:49:39 +02:00
Richard Underwood
9d8d909c18 Remove jtable_respond from the CLI script. 2016-08-24 14:38:03 +01:00
Richard Underwood
f081d96b0c Allow viewing of past logs.
Add a command-line PHP script for rotation in cron.
2016-08-24 14:19:52 +01:00
Richard Underwood
56c1789b30 Changed "Save logs" to "Download logs" for clarity.
Removed the rotate logs icon.
Updated warning text for clearing logs, if rotation is allowed.
2016-08-24 11:42:22 +01:00
Richard Underwood
d1b817443c Initial implementation of log rotation. 2016-08-24 11:32:43 +01:00
Tuxis Internet Engineering V.O.F
a8abca1121 Merge pull request #106 from richard-underwood/issue-90
Implemented logs and zone searching.
Closes: #90
2016-08-23 17:24:33 +02:00
Richard Underwood
708327ecd2 Match capitalisation on toolbar 2016-08-23 16:23:10 +01:00
Richard Underwood
dde58c798c Implemented logs and zone searching. 2016-08-23 15:56:41 +01:00
Mark Schouten
b91317046b Fix logging in cases we don't have a username yet. Also, log more stuff. Closes #104 2016-08-23 12:30:27 +02:00
Mark Schouten
4b5d4b02c9 Fix bug in Exception() and clearify the error message. Closes #100 2016-08-09 22:59:29 +02:00
Mark Schouten
b04b4dd864 Set ttl for the whole rrset if we update a record within that rrset. Might update other records as well, but that's as designed. Should fix #99 2016-08-08 19:13:47 +02:00
17 changed files with 727 additions and 172 deletions

2
.gitignore vendored
View file

@ -1,2 +1,4 @@
includes/config.inc.php
nsedit.sublime*
etc
templates.d/*.json

View file

@ -1,38 +1,28 @@
FROM debian:jessie
FROM debian:bookworm
MAINTAINER Yury Evtikhov <yury@evtikhov.info>
#
# This Dockerfile is intended only for test/development use.
# It will be a really BAD idea to use it for production or public services.
#
#
ENV DEBIAN_FRONTEND noninteractive
#
# Please set the following variables before building:
#
ENV PDNSAPIPWD mypowerdnsapipassword
ENV PDNSAPIIP 192.168.1.2
ENV PDNSAPIPORT 8081
# Update and Upgrade system
RUN apt-get -y update && \
apt-get -y install curl git-core php5-cli php5-curl php5-json php5-sqlite && \
mkdir /app && \
git clone --recursive https://github.com/tuxis-ie/nsedit.git /app/nsedit && \
cp /app/nsedit/includes/config.inc.php-dist /app/nsedit/includes/config.inc.php && \
sed "s/\$apipass = ''/\$apipass = '$PDNSAPIPWD'/" -i /app/nsedit/includes/config.inc.php && \
sed "s/\$apiip = ''/\$apiip = '$PDNSAPIIP'/" -i /app/nsedit/includes/config.inc.php && \
sed "s/\$apiport = ''/\$apiport = '$PDNSAPIPORT'/" -i /app/nsedit/includes/config.inc.php && \
sed "s/\$authdb = \"\.\.\/etc\/pdns\.users\.sqlite3\"/\$authdb = \"\/app\/pdns\.users\.sqlite3\"/" -i /app/nsedit/includes/config.inc.php
apt-get -y install curl git-core php8.2-cli php8.2-curl php8.2-sqlite3 && \
rm -rf /var/lib/apt/lists/*
RUN mkdir /app
RUN git clone --recursive https://github.com/tuxis-ie/nsedit.git /app/nsedit
RUN cp /app/nsedit/includes/config.inc.php-dist /app/nsedit/includes/config.inc.php
COPY docker-entrypoint.sh /app/nsedit/docker-entrypoint.sh
RUN chmod +x /app/nsedit/docker-entrypoint.sh
# Define working directory.
VOLUME /app/nsedit
WORKDIR /app/nsedit
EXPOSE 8080
ENTRYPOINT ["/usr/bin/php", "-S", "0.0.0.0:8080"]
CMD ["sh", "-c", "/app/nsedit/docker-entrypoint.sh"]
#
# Usage:

View file

@ -19,7 +19,7 @@ Features
User support
============
Multiple users are supported. A user can be an admin or a normal user. You can
configure wheter or not a normal user is allowed to add new zones.
configure whether or not a normal user is allowed to add new zones.
WeFact Login support
====================
@ -50,15 +50,21 @@ Installing
* Copy ```includes/config.inc.php-dist``` to ```includes/config.inc.php``` and edit config.inc.php to your needs.
* By default, nsedit writes its user database to ../etc/pdns.users.sqlite3. Be sure that your webserver can create that directory and write to it.
* By default, nsedit writes its user database to ../etc/pdns.users.sqlite3. Be sure that your webserver can create that directory and write to it. **Make sure the Webserver doesn't serve this file/folder to the public!**
* Visit http(s)://<url>/nsedit/ and login with admin/admin (Don't forget to update your password!)
Have fun ;)
Other methods of installation (Unsupported)
===========================================
* Baji Zsolt created a Suse image: https://susestudio.com/a/vvnMqa/powerdns-with-nsedit
* Yury Evtikhov created the Docker file: https://github.com/tuxis-ie/nsedit/blob/master/Dockerfile
Configuring PowerDNS
====================
Minimal cofiguration of PowerDNS for supporting nsedit has to include 3 directives:
Minimal configuration of PowerDNS for supporting nsedit has to include 3 directives:
```
webserver=yes
api=yes

View file

@ -15,6 +15,7 @@ body, html {
border: 1px solid #DDD;
font-family: 'Segoe UI Semilight','Open Sans',Verdana,Arial,Helvetica,sans-serif;
font-weight: 300;
float: left;
font-size: 14px;
line-height: 1.3;
width: 10%;

13
docker-entrypoint.sh Normal file
View file

@ -0,0 +1,13 @@
#!/usr/bin/env bash
[ -z "$PDNSAPIIP" ] && echo "Set PDNSAPIIP to your PowerDNS API IP/Hostname" && exit 1;
[ -z "$PDNSAPIPWD" ] && echo "Set PDNSAPIPWD to your PowerDNS API Password" && exit 1;
sed "s/\$apipass = ''/\$apipass = '$PDNSAPIPWD'/" -i /app/nsedit/includes/config.inc.php
sed "s/\$apiip = ''/\$apiip = '$PDNSAPIIP'/" -i /app/nsedit/includes/config.inc.php
if [[ $PDNSAPIPORT && ${PDNSAPIPORT-x} ]]
then
sed "s/\$apiport = '8081'/\$apiport = '$PDNSAPIPORT'/" -i /app/nsedit/includes/config.inc.php
fi
sed "s/\$authdb = \"\.\.\/etc\/pdns\.users\.sqlite3\"/\$authdb = \"\/app\/pdns\.users\.sqlite3\"/" -i /app/nsedit/includes/config.inc.php
exec /usr/bin/php -S 0.0.0.0:8080

View file

@ -3,6 +3,19 @@
include_once('includes/config.inc.php');
class ApiHandler {
public $headers;
public $hostname;
public $port;
public $auth;
public $proto;
public $sslverify;
public $curlh;
public $method;
public $content;
public $apiurl;
public $url;
public $json;
public function __construct() {
global $apiip, $apiport, $apipass, $apiproto, $apisslverify;
@ -29,22 +42,21 @@ class ApiHandler {
private function apiurl() {
$tmp = new ApiHandler();
$tmp->url = '/api';
$tmp->url = '/api/v1/servers/localhost';
$tmp->go();
if ($tmp->json[0]['version'] <= 1) {
$this->apiurl = $tmp->json[0]['url'];
} else {
throw new Exception("Unsupported API version");
}
$this->apiurl = $tmp->json["url"];
}
private function curlopts() {
$this->authheaders();
$this->addheader('Accept', 'application/json');
curl_reset($this->curlh);
if(defined('curl_reset')) {
curl_reset($this->curlh);
} else {
$this->curlh = curl_init();
}
curl_setopt($this->curlh, CURLOPT_HTTPHEADER, Array());
curl_setopt($this->curlh, CURLOPT_RETURNTRANSFER, 1);
@ -61,7 +73,13 @@ class ApiHandler {
}
private function baseurl() {
return $this->proto.'://'.$this->hostname.':'.$this->port.$this->apiurl;
$ip = $this->hostname;
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$ip = sprintf('[%s]', $ip); // curl needs brackets for IPv6
}
return $this->proto.'://'.$ip.':'.$this->port.$this->apiurl;
}
private function go() {
@ -89,12 +107,6 @@ class ApiHandler {
curl_setopt($this->curlh, CURLOPT_URL, $this->baseurl().$this->url);
//print "Here we go:\n";
//print "Request: ".$this->method.' '.$this->baseurl().$this->url."\n";
//if ($this->content != '') {
// print "Content: ".$this->content."\n";
//}
$return = curl_exec($this->curlh);
$code = curl_getinfo($this->curlh, CURLINFO_HTTP_CODE);
$json = json_decode($return, 1);
@ -112,12 +124,11 @@ class ApiHandler {
}
public function call() {
if (substr($this->url, 0, 1) == '/') {
$this->apiurl();
} else {
$this->apiurl = '/';
if (substr($this->url, 0, 1) != '/') {
$this->url = '/'.$this->url;
}
$this->apiurl();
$this->url = str_replace($this->apiurl, '', $this->url);
$this->go();
}
}

View file

@ -3,6 +3,9 @@
include_once('ApiHandler.php');
class PdnsAPI {
public $http;
public function __construct() {
$this->http = new ApiHandler();
}
@ -11,7 +14,7 @@ class PdnsAPI {
$api = clone $this->http;
$api->method = 'GET';
if ($q) {
$api->url = "/servers/localhost/search-data?q=*".$q."*&max=25";
$api->url = "/search-data?q=*".$q."*&max=25";
$api->call();
$ret = Array();
$seen = Array();
@ -28,7 +31,7 @@ class PdnsAPI {
return $ret;
}
$api->url = "/servers/localhost/zones";
$api->url = "/zones";
$api->call();
return $api->json;
@ -37,7 +40,7 @@ class PdnsAPI {
public function loadzone($zoneid) {
$api = clone $this->http;
$api->method = 'GET';
$api->url = "/servers/localhost/zones/$zoneid";
$api->url = "/zones/$zoneid";
$api->call();
return $api->json;
@ -46,7 +49,7 @@ class PdnsAPI {
public function exportzone($zoneid) {
$api = clone $this->http;
$api->method = 'GET';
$api->url = "/servers/localhost/zones/$zoneid/export";
$api->url = "/zones/$zoneid/export";
$api->call();
return $api->json;
@ -64,7 +67,7 @@ class PdnsAPI {
if (!isset($zone['serial']) or gettype($zone['serial']) != 'integer') {
$api->method = 'POST';
$api->url = '/servers/localhost/zones';
$api->url = '/zones';
$api->content = json_encode($zonedata);
$api->call();
@ -88,7 +91,7 @@ class PdnsAPI {
public function deletezone($zoneid) {
$api = clone $this->http;
$api->method = 'DELETE';
$api->url = "/servers/localhost/zones/$zoneid";
$api->url = "/zones/$zoneid";
$api->call();
return $api->json;
@ -98,7 +101,7 @@ class PdnsAPI {
$ret = array();
$api = clone $this->http;
$api->method = 'GET';
$api->url = "/servers/localhost/zones/$zoneid/cryptokeys";
$api->url = "/zones/$zoneid/cryptokeys";
$api->call();

View file

@ -1,6 +1,21 @@
<?php
class Zone {
public $id;
public $name;
public $kind;
public $url;
public $serial;
public $dnssec;
public $soa_edit;
public $soa_edit_api;
public $keyinfo;
public $account;
public $zone;
public $nameservers;
public $rrsets;
public $masters;
public function __construct() {
$this->id = '';
$this->name = '';
@ -26,10 +41,10 @@ class Zone {
$this->setAccount($data['account']);
$this->setSerial($data['serial']);
$this->url = $data['url'];
if (isset($data['soa_edit']))
if (isset($data['soa_edit']) && $data['soa_edit'] != "")
$this->setSoaEdit($data['soa_edit']);
if (isset($data['soa_edit_api']))
$this->setSoaEditApi($data['soa_edit_api']);
if (isset($data['soa_edit_api']) && $data['soa_edit_api'] != "")
$this->setSoaEditApi($data['soa_edit_api'], True);
foreach ($data['masters'] as $master) {
$this->addMaster($master);
@ -76,7 +91,12 @@ class Zone {
$this->soa_edit = $soaedit;
}
public function setSoaEditApi($soaeditapi) {
public function setSoaEditApi($soaeditapi, $overwrite=False) {
if (isset($this->soa_edit_api) and $this->soa_edit_api != "") {
if ($overwrite === False) {
return False;
}
}
$this->soa_edit_api = $soaeditapi;
}
public function setName($name) {
@ -125,6 +145,7 @@ class Zone {
if ($rrset) {
$rrset->addRecord($content, $disabled, $setptr);
$rrset->setTtl($ttl);
} else {
$this->addRRSet($name, $type, $content, $disabled, $ttl, $setptr);
}
@ -180,8 +201,12 @@ class Zone {
$ret['nameservers'] = $this->nameservers;
$ret['kind'] = $this->kind;
$ret['name'] = $this->name;
$ret['soa_edit'] = $this->soa_edit;
$ret['soa_edit_api'] = $this->soa_edit_api;
if (isset($this->soa_edit) && $this->soa_edit != "") {
$ret['soa_edit'] = $this->soa_edit;
}
if (isset($this->soa_edit_api) && $this->soa_edit_api != "") {
$ret['soa_edit_api'] = $this->soa_edit_api;
}
if ($this->zone) {
$ret['zone'] = $this->zone;
return $ret;
@ -211,6 +236,13 @@ class Zone {
}
class RRSet {
public $name;
public $type;
public $ttl;
public $changetype;
public $records;
public $comments;
public function __construct($name = '', $type = '', $content = '', $disabled = FALSE, $ttl = 3600, $setptr = FALSE) {
$this->name = $name;
$this->type = $type;
@ -239,7 +271,7 @@ class RRSet {
public function addRecord($content, $disabled = FALSE, $setptr = FALSE) {
foreach ($this->records as $record) {
if ($record->content == $content) {
throw Exception("Record already exists");
throw new Exception($this->name."/".$this->type." has duplicate records.");
}
}
@ -296,6 +328,10 @@ class RRSet {
}
class Record {
public $content;
public $disabled;
public $setptr;
public function __construct($content, $disabled = FALSE, $setptr = FALSE) {
$this->content = $content;
$this->disabled = $disabled;
@ -316,6 +352,10 @@ class Record {
}
class Comment {
public $content;
public $account;
public $modified_at;
public function __construct($content, $account, $modified_at) {
$this->content = $content;
$this->account = $account;
@ -328,6 +368,8 @@ class Comment {
$ret['content'] = $this->content;
$ret['account'] = $this->account;
$ret['modified_at'] = $this->modified_at;
return $ret;
}
}

View file

@ -7,7 +7,12 @@ $apiproto = 'http'; # http | https
$apisslverify = FALSE; # Verify SSL Certificate if using https for apiproto
$allowzoneadd = FALSE; # Allow normal users to add zones
$logging = TRUE;
$allowclearlogs = TRUE; # Allow clearing of log entries
$allowrotatelogs = FALSE;# Allow rotation to text file on server
# Log directory - if allowrotatelogs is set, this is where the logs will
# be written. It must be writeable by the web server user.
$logsdirectory = "../etc";
# If you configure this, nsedit will try to authenticate via WeFact too.
# Debtors will be added to the sqlitedatabase with their crypted password.
@ -19,8 +24,13 @@ $logging = TRUE;
#$adminapiips = array();
#$adminapikey = 'thisshouldbequitealongstring,youknow';
# Location of user-database. Make sure its writeable and not served by the webserver!
$authdb = "../etc/pdns.users.sqlite3";
# Admin login and password at first start-up
$default_admin_username = "admin";
$default_admin_password = "admin";
# Set a random generated secret to enable auto-login and long living csrf tokens
// $secret = '...';
@ -30,16 +40,24 @@ $templates[] = array(
'name' => 'Tuxis',
'owner' => 'username', # Set to 'public' to make it available to all users
'records' => array(
array(
'name' => '',
'type' => 'MX',
'content' => '200 mx2.tuxis.nl')
array(
'name' => '',
'type' => 'MX',
'content' => '200 mx2.tuxis.nl.'),
array(
'name' => '',
'type' => 'A',
'content' => '1.2.3.4'),
array(
'name' => 'www',
'type' => 'CNAME',
'content' => '[zonename]')
)
);
*/
$defaults['soa_edit'] = 'INCEPTION-INCREMENT';
$defaults['soa_edit_api'] = 'INCEPTION-INCREMENT';
$defaults['soa_edit_api'] = 'DEFAULT';
$defaults['defaulttype'] = 'Master'; # Choose between 'Native' or 'Master'
$defaults['ns'][0] = 'unconfigured.primaryns.'; # The value of the first NS-record
$defaults['ns'][1] = 'unconfigured.secondaryns.'; # The value of the second NS-record

View file

@ -35,7 +35,7 @@ if (isset($defaults['primaryns'])) {
}
if (!isset($logo) or empty($logo)) {
$logo = 'http://www.tuxis.nl/uploads/images/nsedit.png';
$logo = 'https://www.tuxis.nl/uploads/images/nsedit.png';
}
@ -50,7 +50,7 @@ if (class_exists('SQLite3') === FALSE) {
$errormsg = "You need PHP SQLite3 to run nsedit";
$blocklogin = TRUE;
}
if (function_exists('openssl_random_pseudo_bytes') === FALSE) {
$errormsg = "You need PHP compiled with openssl to run nsedit";
$blocklogin = TRUE;
@ -59,13 +59,20 @@ if (function_exists('openssl_random_pseudo_bytes') === FALSE) {
$defaults['defaulttype'] = ucfirst(strtolower($defaults['defaulttype']));
if (isset($authdb) && !file_exists($authdb) && class_exists('SQLite3')) {
is_dir(dirname($authdb)) || mkdir(dirname($authdb));
$db = new SQLite3($authdb, SQLITE3_OPEN_CREATE|SQLITE3_OPEN_READWRITE);
$createsql = file_get_contents('includes/scheme.sql');
$db->exec($createsql);
$salt = bin2hex(openssl_random_pseudo_bytes(16));
$db->exec("INSERT INTO users (emailaddress, password, isadmin) VALUES ('admin', '".crypt("admin", '$6$'.$salt)."', 1)");
try {
if (isset($authdb) && !file_exists($authdb) && class_exists('SQLite3')) {
is_dir(dirname($authdb)) || mkdir(dirname($authdb));
$db = new SQLite3($authdb, SQLITE3_OPEN_CREATE|SQLITE3_OPEN_READWRITE);
$createsql = file_get_contents('includes/scheme.sql');
$db->exec($createsql);
$salt = bin2hex(openssl_random_pseudo_bytes(16));
$default_admin_username = $default_admin_username ?? "admin";
$default_admin_password = $default_admin_password ?? "admin";
$db->exec("INSERT INTO users (emailaddress, password, isadmin) VALUES ('".$default_admin_username."', '".crypt($default_admin_password, '$6$'.$salt)."', 1)");
}
} catch (Exception $e) {
print("We have issues getting the authdb working: $e");
$blocklogin = TRUE;
}
function string_starts_with($string, $prefix)
@ -85,10 +92,12 @@ function string_ends_with($string, $suffix)
}
function get_db() {
global $authdb;
global $authdb, $db;
$db = new SQLite3($authdb, SQLITE3_OPEN_READWRITE);
$db->exec('PRAGMA foreign_keys = 1');
if (!isset($db)) {
$db = new SQLite3($authdb, SQLITE3_OPEN_READWRITE);
$db->exec('PRAGMA foreign_keys = 1');
}
return $db;
}
@ -110,7 +119,6 @@ function get_user_info($u) {
$q->bindValue(1, $u);
$result = $q->execute();
$userinfo = $result->fetchArray(SQLITE3_ASSOC);
$db->close();
return $userinfo;
}
@ -125,10 +133,8 @@ function do_db_auth($u, $p) {
$q->bindValue(1, $u);
$result = $q->execute();
$userinfo = $result->fetchArray(SQLITE3_ASSOC);
$db->close();
if ($userinfo and $userinfo['password'] and (crypt($p, $userinfo['password']) === $userinfo['password'])) {
writelog('Succesful login.');
return TRUE;
}
@ -150,7 +156,6 @@ function add_user($username, $isadmin = FALSE, $password = '') {
$q->bindValue(2, $password, SQLITE3_TEXT);
$q->bindValue(3, (int)(bool) $isadmin, SQLITE3_INTEGER);
$ret = $q->execute();
$db->close();
if ($isadmin) {
writelog("Added user $username as admin.");
@ -160,7 +165,7 @@ function add_user($username, $isadmin = FALSE, $password = '') {
return $ret;
}
function update_user($username, $isadmin, $password) {
function update_user($id, $isadmin, $password) {
if ($password && !preg_match('/\$6\$/', $password)) {
$salt = bin2hex(openssl_random_pseudo_bytes(16));
$password = crypt($password, '$6$'.$salt);
@ -168,33 +173,49 @@ function update_user($username, $isadmin, $password) {
$db = get_db();
$q = $db->prepare('SELECT * FROM users WHERE id = ?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$result = $q->execute();
$userinfo = $result->fetchArray(SQLITE3_ASSOC);
$q->close();
$username = $userinfo['emailaddress'];
if ($password) {
$q = $db->prepare('UPDATE users SET isadmin = ?, password = ? WHERE emailaddress = ?');
$q = $db->prepare('UPDATE users SET isadmin = ?, password = ? WHERE id = ?');
$q->bindValue(1, (int)(bool)$isadmin, SQLITE3_INTEGER);
$q->bindValue(2, $password, SQLITE3_TEXT);
$q->bindValue(3, $username, SQLITE3_TEXT);
$q->bindValue(3, $id, SQLITE3_INTEGER);
writelog("Updating password and/or settings for $username. Admin: ".(int)(bool)$isadmin);
} else {
$q = $db->prepare('UPDATE users SET isadmin = ? WHERE emailaddress = ?');
$q = $db->prepare('UPDATE users SET isadmin = ? WHERE id = ?');
$q->bindValue(1, (int)(bool)$isadmin, SQLITE3_INTEGER);
$q->bindValue(2, $username, SQLITE3_TEXT);
$q->bindValue(2, $id, SQLITE3_INTEGER);
writelog("Updating settings for $username. Admin: ".(int)(bool)$isadmin);
}
$ret = $q->execute();
$db->close();
return $ret;
}
function delete_user($username) {
function delete_user($id) {
$db = get_db();
$q = $db->prepare('DELETE FROM users WHERE id = ?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$ret = $q->execute();
$db->close();
writelog("Deleted user $username.");
return $ret;
$q = $db->prepare('SELECT * FROM users WHERE id = ?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$result = $q->execute();
$userinfo = $result->fetchArray(SQLITE3_ASSOC);
$q->close();
if($userinfo) {
$q = $db->prepare('DELETE FROM users WHERE id = ?');
$q->bindValue(1, $id, SQLITE3_INTEGER);
$ret = $q->execute();
writelog("Deleted user " . $userinfo['emailaddress'] . ".");
return $ret;
} else {
return false;
}
}
function valid_user($name) {
@ -224,6 +245,8 @@ function jtable_respond($records, $method = 'multiple', $msg = 'Undefined errorm
$jTableResult['RecordCount'] = count($records);
}
$db = get_db();
$db->close();
header('Content-Type: application/json');
print json_encode($jTableResult);
exit(0);
@ -232,6 +255,27 @@ function jtable_respond($records, $method = 'multiple', $msg = 'Undefined errorm
function user_template_list() {
global $templates;
if (is_dir("templates.d")) {
if ($templdir=opendir("templates.d")) {
while ($entry = readdir($templdir)) {
if (!str_ends_with($entry, ".json")) {
continue;
}
$f=file_get_contents("templates.d/$entry");
if ($f === false) {
error_log("Error reading file templates.d/$entry", 0);
continue;
}
$t = json_decode($f, true);
if ($t === null) {
error_log("Error decoding templates.d/$entry", 0);
continue;
}
array_push($templates, $t);
}
}
}
$templatelist = array();
foreach ($templates as $template) {
if (is_adminuser()
@ -273,15 +317,70 @@ function clearlogs() {
$db = get_db();
$q = $db->query('DELETE FROM logs;');
$db->close();
writelog("Logtable truncated.");
}
function writelog($line) {
function rotatelogs() {
global $logging, $logsdirectory;
if ($logging !== TRUE)
return FALSE;
if(!is_dir($logsdirectory) || !is_writable($logsdirectory)) {
writelog("Logs directory cannot be written to.");
return FALSE;
}
date_default_timezone_set('UTC');
$filename = date("Y-m-d-His") . ".json";
$file = fopen($logsdirectory . "/" . $filename, "x");
if($file === FALSE) {
writelog("Can't create file for log rotation.");
return FALSE;
}
if(fwrite($file,json_encode(getlogs())) === FALSE) {
writelog("Can't write to file for log rotation.");
fclose($file);
return FALSE;
} else {
fclose($file);
clearlogs();
return $filename;
}
}
function listrotatedlogs() {
global $logging, $logsdirectory;
if ($logging !== TRUE)
return FALSE;
$list = scandir($logsdirectory,SCANDIR_SORT_DESCENDING);
if($list === FALSE) {
writelog("Logs directory cannot read.");
return FALSE;
}
$list=array_filter($list,
function ($val) {
return(preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{6}\.json/',$val) == 1);
}
);
return $list;
}
function writelog($line, $user=False) {
global $logging;
if ($logging !== TRUE)
return;
if ($user === False) {
$user = get_sess_user();
}
try {
$db = get_db();
$q = $db->prepare('CREATE TABLE IF NOT EXISTS logs (
@ -292,10 +391,9 @@ function writelog($line) {
$ret = $q->execute();
$q = $db->prepare('INSERT INTO logs (user, log) VALUES (:user, :log)');
$q->bindValue(':user', get_sess_user(), SQLITE3_TEXT);
$q->bindValue(':user', $user, SQLITE3_TEXT);
$q->bindValue(':log', $line, SQLITE3_TEXT);
$q->execute();
$db->close();
} catch (Exception $e) {
return jtable_respond(null, 'error', $e->getMessage());
}

View file

@ -9,11 +9,13 @@ global $current_user;
$current_user = false;
// session startup
function _set_current_user($username, $is_admin = false, $has_csrf_token = false, $is_api = false) {
function _set_current_user($username, $userid, $localauth = true, $is_admin = false, $has_csrf_token = false, $is_api = false) {
global $current_user;
$current_user = array(
'username' => $username,
'id' => $userid,
'localauth' => $localauth,
'is_admin' => $is_admin,
'has_csrf_token' => $has_csrf_token,
'is_api' => $is_api,
@ -50,7 +52,7 @@ function _check_csrf_token($user) {
}
define('CSRF_TOKEN', $csrf_token);
header("X-CSRF-Token: ${csrf_token}");
header("X-CSRF-Token: {$csrf_token}");
}
function enc_secret($message) {
@ -120,13 +122,13 @@ function dec_secret($code) {
function _unset_cookie($name) {
$is_ssl = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off';
setcookie($name, null, -1, null, null, $is_ssl);
setcookie($name, "", -1, "", "", $is_ssl);
}
function _store_auto_login($value) {
$is_ssl = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off';
// set for 30 days
setcookie('NSEDIT_AUTOLOGIN', $value, time()+60*60*24*30, null, null, $is_ssl);
setcookie('NSEDIT_AUTOLOGIN', $value, time()+60*60*24*30, "", "", $is_ssl);
}
function try_login() {
@ -150,6 +152,7 @@ function _try_login($username, $password) {
global $wefactapiurl, $wefactapikey;
if (!valid_user($username)) {
writelog("Illegal username at login!", $username);
return false;
}
@ -158,6 +161,7 @@ function _try_login($username, $password) {
if (isset($wefactapiurl) && isset($wefactapikey)) {
$wefact = do_wefact_auth($username, $password);
if (false === $wefact ) {
writelog("Failed Wefact login!", $username);
return false;
}
if (-1 !== $wefact) {
@ -166,14 +170,16 @@ function _try_login($username, $password) {
}
if ($do_local_auth && !do_db_auth($username, $password)) {
writelog("Failed login!", $username);
return false;
}
$user = get_user_info($username);
if (!$user) {
writelog("Failed to find user!", $username);
return false;
} else {
_set_current_user($username, (bool) $user['isadmin']);
_set_current_user($username, $user['id'], (bool) $do_local_auth, (bool) $user['isadmin']);
if (session_id()) {
session_unset();
@ -183,6 +189,8 @@ function _try_login($username, $password) {
session_regenerate_id(true) or die('session failure: regenerated id failed');
session_unset();
$_SESSION['username'] = $username;
$_SESSION['localauth'] = $do_local_auth;
$_SESSION['userid'] = $user['id'];
# requires session:
_check_csrf_token($user);
@ -202,7 +210,7 @@ function _check_session() {
and $_POST['adminapikey'] === $adminapikey)
{
# Allow this request, fake that we're logged in as user.
return _set_current_user('admin', true, true, true);
return _set_current_user('admin', 1, false, true, true, true);
}
else
{
@ -218,7 +226,7 @@ function _check_session() {
session_destroy();
session_unset();
} else {
_set_current_user($_SESSION['username'], (bool) $user['isadmin']);
_set_current_user($_SESSION['username'], $_SESSION['userid'], (bool) $_SESSION['localauth'], (bool) $user['isadmin']);
_check_csrf_token($user);
return;
}
@ -277,6 +285,16 @@ function get_sess_user() {
return $current_user ? $current_user['username'] : null;
}
function get_sess_userid() {
global $current_user;
return $current_user ? $current_user['id'] : null;
}
function has_local_auth() {
global $current_user;
return $current_user ? $current_user['localauth'] : null;
}
function logout() {
@session_destroy();
@session_unset();

236
index.php
View file

@ -6,6 +6,12 @@ include_once('includes/misc.inc.php');
global $errormsg, $blocklogin;
$docroot = $_SERVER['DOCUMENT_ROOT'];
if (preg_match("@$docroot@", $authdb) == 1) {
$blocklogin = TRUE;
$errormsg = "You authdb is in your document root and probably downloadable. Please move it to a safe location!";
}
if (isset($_GET['logout']) or isset($_POST['logout'])) {
logout();
header("Location: index.php");
@ -20,7 +26,7 @@ if (!is_logged_in() and isset($_POST['formname']) and $_POST['formname'] === "lo
if (is_logged_in() and isset($_POST['formname']) and $_POST['formname'] === "changepwform") {
if (get_sess_user() == $_POST['username']) {
if (!update_user(get_sess_user(), is_adminuser(), $_POST['password'])) {
if (!update_user(get_sess_userid(), is_adminuser(), $_POST['password'])) {
$errormsg = "Unable to update password!\n";
}
} else {
@ -114,7 +120,45 @@ if ($blocklogin === TRUE) {
<div id="dnssecinfo">
</div>
<div id="clearlogs" style="display: none;">
Are you sure you want to clear all the logs? Maybe save them first?
Are you sure you want to clear the current logs? Maybe download them
first<?php if($allowrotatelogs) { ?>, or use "Rotate logs" to save
them on the server<?php } ?>?
</div>
<div id="rotatelogs" style="display: none;">
Are you sure you want to rotate the current logs?
</div>
<div id="searchlogs" style="display: none; text-align: right;">
<table border="0">
<tr><td>User:</td><td><input type="text" id ="searchlogs-user"><br></td></tr>
<tr><td>Log Entry:</td><td><input type="text" id ="searchlogs-entry"></td></tr>
</table>
</div>
<div id="searchzone" style="display: none; text-align: right;">
<table border="0">
<tr><td>Label:</td><td><input type="text" id ="searchzone-label"><br></td></tr>
<tr><td>Type:</td><td style="text-align: left;"><select id="searchzone-type">
<option value=""></option>
<option value="A">A</option>
<option value="AAAA">AAAA</option>
<option value="CERT">CERT</option>
<option value="CNAME">CNAME</option>
<option value="ALIAS">ALIAS</option>
<option value="LOC">LOC</option>
<option value="MX">MX</option>
<option value="NAPTR">NAPTR</option>
<option value="NS">NS</option>
<option value="PTR">PTR</option>
<option value="SOA">SOA</option>
<option value="SPF">SPF</option>
<option value="SRV">SRV</option>
<option value="SSHFP">SSHFP</option>
<option value="TLSA">TLSA</option>
<option value="CAA">CAA</option>
<option value="TXT">TXT</option>
<option value="SMIMEA">SMIMEA</option>
</select><br></td></tr>
<tr><td>Content:</td><td><input type="text" id ="searchzone-content"></td></tr>
</table>
</div>
<div id="menu" class="jtable-main-container <?php if ($menutype === 'horizontal') { ?>horizontal<?php } ?>">
<div class="jtable-title menu-title">
@ -137,9 +181,11 @@ if ($blocklogin === TRUE) {
}
?>
<div id="zones">
<?php if (is_adminuser() or $allowzoneadd === TRUE) { ?>
<div style="visibility: hidden;" id="ImportZone"></div>
<div style="visibility: hidden;" id="CloneZone"></div>
<?php if ($allowzoneadd === TRUE) { ?>
<div style="display: none;" id="ImportZone"></div>
<?php } ?>
<?php if (is_adminuser()) { ?>
<div style="display: none;" id="CloneZone"></div>
<?php } ?>
<div class="tables" id="MasterZones">
<div class="searchbar" id="searchbar">
@ -154,9 +200,25 @@ if ($blocklogin === TRUE) {
</div>
<div id="logs">
<div class="tables" id="Logs"></div>
<?php if($allowrotatelogs) { ?>
<br>Log entries being viewed:
<select id="logfile">
<option value="">(Current logs)</option>
<?php
$logfiles=listrotatedlogs();
if($logfiles !== FALSE) {
foreach ($logfiles as $filename) {
echo '<option value="' . $filename . '">' . str_replace(".json","",$filename) . "</option>\n";
}
}
?></select>
<?php } else { ?>
<input type="hidden" id="logfile" value="">
<?php } ?>
</div>
<?php } ?>
<?php if (has_local_auth()) { ?>
<div id="AboutMe">
<div class="tables">
<p>Hi <?php echo get_sess_user(); ?>. You can change your password here.</p>
@ -181,9 +243,11 @@ if ($blocklogin === TRUE) {
</tr>
</table>
<input type="hidden" name="formname" value="changepwform">
<input type="hidden" name="id" value="<?php echo get_sess_userid(); ?>">
</form>
</div>
</div>
<?php } ?>
</div>
<script type="text/javascript">
window.csrf_token = '<?php echo CSRF_TOKEN ?>';
@ -441,7 +505,7 @@ $(document).ready(function () {
hoverAnimationDuration: 60,
hoverAnimationEasing: undefined,
items: [
<?php if (is_adminuser() or $allowzoneadd === TRUE) { ?>
<?php if ($allowzoneadd === TRUE) { ?>
{
icon: 'jtable/lib/themes/metro/add.png',
text: 'Import a new zone',
@ -449,6 +513,8 @@ $(document).ready(function () {
$('#ImportZone').jtable('showCreateForm');
}
},
<?php } ?>
<?php if (is_adminuser()) { ?>
{
icon: 'jtable/lib/themes/metro/add.png',
text: 'Clone a zone',
@ -473,6 +539,40 @@ $(document).ready(function () {
addNewRecord: 'Add to ' + zone.name,
noDataAvailable: 'No records for ' + zone.name
},
toolbar: {
items: [
{
text: 'Search zone',
click: function() {
$("#searchzone").dialog({
modal: true,
title: "Search zone for ...",
width: 'auto',
buttons: {
Search: function() {
$( this ).dialog( 'close' );
opentable.find('.jtable-title-text').text(opentableTitle + " (filtered)");
opentable.jtable('load', {
label: $('#searchzone-label').val(),
type: $('#searchzone-type').val(),
content: $('#searchzone-content').val()
});
},
Reset: function() {
$('#searchzone-label').val('');
$('#searchzone-type').val('');
$('#searchzone-content').val('');
$( this ).dialog( 'close' );
opentable.find('.jtable-title-text').text(opentableTitle);
opentable.jtable('load');
return false;
}
}
});
}
}
],
},
paging: true,
sorting: true,
pageSize: 20,
@ -526,12 +626,17 @@ $(document).ready(function () {
'AAAA': 'AAAA',
'CERT': 'CERT',
'CNAME': 'CNAME',
'ALIAS': 'ALIAS',
'LOC': 'LOC',
'NAPTR': 'NAPTR',
'SPF': 'SPF',
'SRV': 'SRV',
'SSHFP': 'SSHFP',
'TLSA': 'TLSA',
'CAA': 'CAA',
'DNAME': 'DNAME',
'DS': 'DS',
'SMIMEA': 'SMIMEA'
};
}
return {
@ -539,6 +644,9 @@ $(document).ready(function () {
'AAAA': 'AAAA',
'CERT': 'CERT',
'CNAME': 'CNAME',
'DNAME': 'DNAME',
'ALIAS': 'ALIAS',
'DS': 'DS',
'LOC': 'LOC',
'MX': 'MX',
'NAPTR': 'NAPTR',
@ -549,7 +657,9 @@ $(document).ready(function () {
'SRV': 'SRV',
'SSHFP': 'SSHFP',
'TLSA': 'TLSA',
'CAA': 'CAA',
'TXT': 'TXT',
'SMIMEA': 'SMIMEA'
};
},
display: displayContent('type'),
@ -609,6 +719,8 @@ $(document).ready(function () {
},
}
}, function (data) {
opentable=data.childTable;
opentableTitle=opentable.find('.jtable-title-text').text();
data.childTable.jtable('load');
});
});
@ -758,7 +870,7 @@ $(document).ready(function () {
type: 'checkbox',
values: {'0': 'No', '1': 'Yes'},
defaultValue: 1,
inputClass: 'overwrite_namerserver'
inputClass: 'overwrite_nameserver'
},
nameserver: {
title: 'Nameservers',
@ -779,7 +891,6 @@ $(document).ready(function () {
}
});
$('#CloneZone').jtable({
title: 'Clone zone',
actions: {
@ -854,18 +965,18 @@ $(document).ready(function () {
});
<?php if (is_adminuser()) { ?>
$('#Logs').hide();
$('#logs').hide();
$('#Users').hide();
$('#AboutMe').hide();
$('#aboutme').click(function () {
$('#Logs').hide();
$('#logs').hide();
$('#Users').hide();
$('#MasterZones').hide();
$('#SlaveZones').hide();
$('#AboutMe').show();
});
$('#useradmin').click(function () {
$('#Logs').hide();
$('#logs').hide();
$('#MasterZones').hide();
$('#SlaveZones').hide();
$('#AboutMe').hide();
@ -873,7 +984,7 @@ $(document).ready(function () {
$('#Users').show();
});
$('#zoneadmin').click(function () {
$('#Logs').hide();
$('#logs').hide();
$('#Users').hide();
$('#AboutMe').hide();
$('#MasterZones').show();
@ -884,8 +995,10 @@ $(document).ready(function () {
$('#AboutMe').hide();
$('#MasterZones').hide();
$('#SlaveZones').hide();
$('#Logs').jtable('load');
$('#Logs').show();
$('#Logs').jtable('load', {
logfile: $('#logfile').val()
});
$('#logs').show();
});
$('#Users').jtable({
title: 'Users',
@ -903,12 +1016,15 @@ $(document).ready(function () {
deleteConfirmation: 'This user will be deleted. Are you sure?'
},
fields: {
id: {
key: true,
type: 'hidden'
},
emailaddress: {
title: 'User',
key: true,
display: displayContent('emailaddress'),
inputClass: 'emailaddress',
create: true,
edit: false,
listClass: 'emailaddress'
},
password: {
@ -938,8 +1054,7 @@ $(document).ready(function () {
pageSize: 20,
sorting: false,
actions: {
listAction: 'logs.php?action=list',
deleteAction: 'logs.php?action=delete',
listAction: 'logs.php?action=list'
},
messages: {
deleteConfirmation: 'This entry will be deleted. Are you sure?'
@ -949,6 +1064,62 @@ $(document).ready(function () {
hoverAnimationDuration: 60,
hoverAnimationEasing: undefined,
items: [
{
text: 'Search logs',
click: function() {
$("#searchlogs").dialog({
modal: true,
title: "Search logs for ...",
width: 'auto',
buttons: {
Search: function() {
$( this ).dialog( 'close' );
$('#Logs').find('.jtable-title-text').text('Logs (filtered)');
$('#Logs').jtable('load', {
logfile: $('#logfile').val(),
user: $('#searchlogs-user').val(),
entry: $('#searchlogs-entry').val()
});
},
Reset: function() {
$('#searchlogs-user').val('');
$('#searchlogs-entry').val('');
$( this ).dialog( 'close' );
$('#Logs').find('.jtable-title-text').text('Logs');
$('#Logs').jtable('load', {
logfile: $('#logfile').val()
});
return false;
}
}
});
}
},
<?php if($allowrotatelogs === TRUE) { ?>
{
text: 'Rotate logs',
click: function() {
$("#rotatelogs").dialog({
modal: true,
title: "Rotate logs",
width: 'auto',
buttons: {
Ok: function() {
$.get("logs.php?action=rotate");
$( this ).dialog( "close" );
$('#logfile').val('');
$('#Logs').jtable('load');
},
Cancel: function() {
$( this ).dialog( "close" );
return false;
}
}
});
}
},
<?php } ?>
<?php if($allowclearlogs === TRUE) { ?>
{
icon: 'img/delete_inverted.png',
text: 'Clear logs',
@ -961,6 +1132,7 @@ $(document).ready(function () {
Ok: function() {
$.get("logs.php?action=clear");
$( this ).dialog( "close" );
$('#logfile').val('');
$('#Logs').jtable('load');
},
Cancel: function() {
@ -971,17 +1143,18 @@ $(document).ready(function () {
});
}
},
<?php } ?>
{
icon: 'img/export.png',
text: 'Save logs',
text: 'Download logs',
click: function () {
var $zexport = $.get("logs.php?action=export", function(data) {
var $zexport = $.get("logs.php?action=export&logfile=" + $('#logfile').val(), function(data) {
console.log(data);
blob = new Blob([data], { type: 'text/plain' });
var dl = document.createElement('a');
dl.addEventListener('click', function(ev) {
dl.href = URL.createObjectURL(blob);
dl.download = 'nseditlogs.txt';
dl.download = $('#logfile').val() == "" ? 'nseditlogs.txt':$('#logfile').val() + ".txt";
}, false);
if (document.createEvent) {
@ -1017,6 +1190,27 @@ $(document).ready(function () {
}
}
});
$('#logfile').change(function () {
$('#Logs').jtable('load', {
logfile: $('#logfile').val(),
user: $('#searchlogs-user').val(),
entry: $('#searchlogs-entry').val()
});
});
<?php } else { ?>
$('#AboutMe').hide();
$('#aboutme').click(function () {
$('#MasterZones').hide();
$('#SlaveZones').hide();
$('#AboutMe').show();
});
$('#zoneadmin').click(function () {
$('#AboutMe').hide();
$('#MasterZones').show();
$('#SlaveZones').show();
});
<?php } ?>
$('#MasterZones').jtable('load');
$('#SlaveZones').jtable('load');

View file

@ -20,32 +20,77 @@ if (!isset($_GET['action'])) {
jtable_respond(null, 'error', 'No action given');
}
switch ($_GET['action']) {
if ($logging !== TRUE) {
jtable_respond(null, 'error', 'Logging is disabled');
} else {
switch ($_GET['action']) {
case "list":
if(!empty($_POST['logfile'])) {
if(preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{6}\.json/',$_POST['logfile']) == 1) {
$entries=json_decode(file_get_contents($logsdirectory . "/" . $_POST['logfile']),true);
} else {
jtable_respond(null, 'error', "Can't find log file");
break;
}
} else {
$entries=getlogs();
}
case "list":
global $logging;
if ($logging !== TRUE)
jtable_respond(null, 'error', 'Logging is disabled');
if(!empty($_POST['user'])) {
$entries=array_filter($entries,
function ($val) {
return(stripos($val['user'], $_POST['user']) !== FALSE);
}
);
}
jtable_respond(getlogs());
break;
if(!empty($_POST['entry'])) {
$entries=array_filter($entries,
function ($val) {
return(stripos($val['log'], $_POST['entry']) !== FALSE);
}
);
}
case "delete":
if ($emailaddress != '' and delete_user($emailaddress) !== FALSE) {
jtable_respond(null, 'delete');
} else {
jtable_respond(null, 'error', 'Could not delete user');
jtable_respond($entries);
break;
case "export":
if(!empty($_GET['logfile'])) {
if(preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{6}\.json/',$_GET['logfile']) == 1) {
$entries=json_decode(file_get_contents($logsdirectory . "/" . $_GET['logfile']),true);
} else {
jtable_respond(null, 'error', "Can't find log file");
break;
}
} else {
$entries=getlogs();
}
if(defined('JSON_PRETTY_PRINT')) {
print json_encode($entries,JSON_PRETTY_PRINT);
} else {
print json_encode($entries);
}
break;
case "clear":
if($allowclearlogs === TRUE) {
clearlogs();
} else {
jtable_respond(null, 'error', 'Invalid action');
}
break;
case "rotate":
if($allowrotatelogs === TRUE) {
rotatelogs();
} else {
jtable_respond(null, 'error', 'Invalid action');
}
break;
default:
jtable_respond(null, 'error', 'Invalid action');
break;
}
break;
case "export":
print json_encode(getlogs());
break;
case "clear":
clearlogs();
break;
default:
jtable_respond(null, 'error', 'Invalid action');
break;
}

16
rotate-logs.php Normal file
View file

@ -0,0 +1,16 @@
<?php
include_once('includes/config.inc.php');
include_once('includes/session.inc.php');
include_once('includes/misc.inc.php');
if(php_sapi_name() !== 'cli') {
echo "This script is intended to be run from the command line";
} else {
if($allowrotatelogs === TRUE) {
$current_user['username']='<system>';
rotatelogs();
} else {
echo "Rotating logs has been disabled."
}
}

View file

@ -0,0 +1,28 @@
{
"name": "Example Template",
"owner": "public",
"records": [
{
"name": "",
"type": "NS",
"content": "ns1.example.com.",
"label": "ns1"
},
{
"name": "",
"type": "NS",
"content": "ns2.example.com.",
"label": "ns2"
},
{
"name": "example-txt",
"type": "TXT",
"content": "This is an example txt record"
},
{
"name": "localhost",
"type": "A",
"content": "127.0.0.1"
}
]
}

View file

@ -64,20 +64,13 @@ case "create":
break;
case "update":
$id = isset($_POST['id']) ? intval($_POST['id']) : '';
$emailaddress = isset($_POST['emailaddress']) ? $_POST['emailaddress'] : '';
$isadmin = isset($_POST['isadmin']) ? $_POST['isadmin'] : '0';
$password = isset($_POST['password']) ? $_POST['password'] : '';
if (!valid_user($emailaddress)) {
jtable_respond(null, 'error', "Please only use ^[a-z0-9@_.-]+$ for usernames");
}
if (!user_exists($emailaddress)) {
jtable_respond(null, 'error', 'Cannot update not existing user');
}
if (update_user($emailaddress, $isadmin, $password)) {
$result = array('emailaddress' => $emailaddress, 'isadmin' => $isadmin);
if ($id != '' and update_user($id, $isadmin, $password)) {
$result = array('isadmin' => $isadmin);
jtable_respond($result, 'single');
} else {
jtable_respond(null, 'error', 'Could not update user');
@ -85,7 +78,9 @@ case "update":
break;
case "delete":
if ($emailaddress != '' and delete_user($emailaddress) !== FALSE) {
$id = isset($_POST['id']) ? intval($_POST['id']) : '';
if ($id != '' and delete_user($id) !== FALSE) {
jtable_respond(null, 'delete');
} else {
jtable_respond(null, 'error', 'Could not delete user');

101
zones.php
View file

@ -12,10 +12,12 @@ if (!is_csrf_safe()) {
jtable_respond(null, 'error', "Authentication required");
}
$quoteus = array('TXT', 'SPF');
/* This function is taken from:
http://pageconfig.com/post/how-to-validate-ascii-text-in-php and got fixed by
#powerdns */
function is_ascii($string) {
return ( bool ) ! preg_match( '/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x80-\\xff]/' , $string );
}
@ -112,7 +114,6 @@ function add_db_zone($zonename, $accountname) {
$q->bindValue(1, $zonename, SQLITE3_TEXT);
$q->bindValue(2, $accountname, SQLITE3_TEXT);
$q->execute();
$db->close();
}
function delete_db_zone($zonename) {
@ -123,7 +124,6 @@ function delete_db_zone($zonename) {
$q = $db->prepare("DELETE FROM zones WHERE zone = ?");
$q->bindValue(1, $zonename, SQLITE3_TEXT);
$q->execute();
$db->close();
}
function get_zone_account($zonename, $default) {
@ -135,7 +135,6 @@ function get_zone_account($zonename, $default) {
$q->bindValue(1, $zonename, SQLITE3_TEXT);
$result = $q->execute();
$zoneinfo = $result->fetchArray(SQLITE3_ASSOC);
$db->close();
if (isset($zoneinfo['emailaddress']) && $zoneinfo['emailaddress'] != null ) {
return $zoneinfo['emailaddress'];
}
@ -143,6 +142,16 @@ function get_zone_account($zonename, $default) {
return $default;
}
function quote_content($content) {
# empty TXT records are ok, otherwise require surrounding quotes: "..."
if (strlen($content) == 1 || substr($content, 0, 1) !== '"' || substr($content, -1) !== '"') {
# fix quoting: first escape all \, then all ", then surround with quotes.
$content = '"'.str_replace('"', '\\"', str_replace('\\', '\\\\', $content)).'"';
}
return $content;
}
function check_account($zone) {
return is_adminuser() or ($zone->account === get_sess_user());
}
@ -165,7 +174,9 @@ case "listslaves":
foreach ($api->listzones($q) as $sresult) {
$zone = new Zone();
$zone->parse($sresult);
$zone->setAccount(get_zone_account($zone->name, 'admin'));
if ($zone->account == '') {
$zone->setAccount(get_zone_account($zone->name, 'admin'));
}
if (!check_account($zone))
continue;
@ -188,6 +199,31 @@ case "listrecords":
$zone = new Zone();
$zone->parse($zonedata);
$records = $zone->rrsets2records();
if(!empty($_POST['label'])) {
$records=array_filter($records,
function ($val) {
return(stripos($val['name'], $_POST['label']) !== FALSE);
}
);
}
if(!empty($_POST['type'])) {
$records=array_filter($records,
function ($val) {
return($val['type'] == $_POST['type']);
}
);
}
if(!empty($_POST['content'])) {
$records=array_filter($records,
function ($val) {
return(stripos($val['content'], $_POST['content']) !== FALSE);
}
);
}
if (isset($_GET['jtSorting'])) {
list($scolumn, $sorder) = preg_split("/ /", $_GET['jtSorting']);
switch ($scolumn) {
@ -248,7 +284,7 @@ case "create":
$zone->importData($_POST['zone']);
}
if (isset($defaults['soa_edit_api'])) {
$zone->setSoaEditApi($defaults['soa_edit_api']);
$zone->setSoaEditApi($defaults['soa_edit_api'], True);
}
if (isset($defaults['soa_edit'])) {
$zone->setSoaEdit($defaults['soa_edit']);
@ -286,7 +322,7 @@ case "create":
if ($template['name'] !== $_POST['template']) continue;
foreach ($template['records'] as $record) {
$rrset = $zone->getRRSet($record['label'], $record['type']);
$rrset = $zone->getRRSet($record['name'], $record['type']);
if ($rrset) {
$rrset->delete();
}
@ -294,7 +330,10 @@ case "create":
$api->savezone($zone->export());
foreach ($template['records'] as $record) {
$zone->addRecord($record['name'], $record['type'], $record['content']);
if ($record['type'] == 'NS') continue;
$name = $record['name'] != '' ? join(Array($record['name'],'.',$zonename)) : $zonename;
$record['content'] = str_replace("[zonename]", $zonename, $record['content']);
$zone->addRecord($name, $record['type'], $record['content']);
}
break;
@ -309,6 +348,8 @@ case "create":
case "update":
$zone = new Zone();
$zone->parse($api->loadzone($_POST['id']));
if ($zone->setSoaEditApi($defaults['soa_edit_api']) != False)
writelog("Set SOA-EDIT-API to ".$defaults['soa_edit_api']." for ",$zone->name);
$zoneaccount = isset($_POST['account']) ? $_POST['account'] : $zone->account;
if ($zone->account !== $zoneaccount) {
@ -335,6 +376,8 @@ case "update":
case "createrecord":
$zone = new Zone();
$zone->parse($api->loadzone($_GET['zoneid']));
if ($zone->setSoaEditApi($defaults['soa_edit_api']) != False)
writelog("Set SOA-EDIT-API to ".$defaults['soa_edit_api']." for ",$zone->name);
$name = isset($_POST['name']) ? $_POST['name'] : '';
$type = $_POST['type'];
@ -344,12 +387,13 @@ case "createrecord":
$name = $zone->name;
} elseif (string_ends_with($name, '.')) {
# "absolute" name, shouldn't append zone[name] - but check.
$name = substr($name, 0, -1);
if (!string_ends_with($name, $zone->name)) {
jtable_respond(null, 'error', "Name $name not in zone ".$zone->name);
}
} else if (!string_ends_with($name, $zone->name)) {
} else if (!string_ends_with($name.'.', $zone->name)) {
$name = $name . '.' . $zone->name;
} else {
$name = $name.'.';
}
if (!_valid_label($name)) {
@ -362,6 +406,10 @@ case "createrecord":
jtable_respond(null, 'error', "Please only use ASCII-characters in your fields");
}
if (array_search($type, $quoteus) !== FALSE) {
$content = quote_content($content);
}
$record = $zone->addRecord($name, $type, $content, $_POST['disabled'], $_POST['ttl'], $_POST['setptr']);
$api->savezone($zone->export());
@ -372,16 +420,25 @@ case "createrecord":
case "editrecord":
$zone = new Zone();
$zone->parse($api->loadzone($_GET['zoneid']));
if ($zone->setSoaEditApi($defaults['soa_edit_api']) != False)
writelog("Set SOA-EDIT-API to ".$defaults['soa_edit_api']." for ",$zone->name);
$old_record = decode_record_id(isset($_POST['id']) ? $_POST['id'] : '');
$rrset = $zone->getRRSet($old_record['name'], $old_record['type']);
$rrset->deleteRecord($old_record['content']);
$zone->addRecord($_POST['name'], $_POST['type'], $_POST['content'], $_POST['disabled'], $_POST['ttl'], $_POST['setptr']);
$content = $_POST['content'];
$type = $_POST['type'];
if (array_search($type, $quoteus) !== FALSE) {
$content = quote_content($content);
}
$zone->addRecord($_POST['name'], $_POST['type'], $content, $_POST['disabled'], $_POST['ttl'], $_POST['setptr']);
$api->savezone($zone->export());
$record = $zone->getRecord($_POST['name'], $_POST['type'], $_POST['content']);
$record = $zone->getRecord($_POST['name'], $_POST['type'], $content);
writelog("Updated record ".$_POST['id']." to ".$record['id']);
jtable_respond($record, 'single');
break;
@ -389,6 +446,8 @@ case "editrecord":
case "deleterecord":
$zone = new Zone();
$zone->parse($api->loadzone($_GET['zoneid']));
if ($zone->setSoaEditApi($defaults['soa_edit_api']) != False)
writelog("Set SOA-EDIT-API to ".$defaults['soa_edit_api']." for ",$zone->name);
$old_record = decode_record_id(isset($_POST['id']) ? $_POST['id'] : '');
$rrset = $zone->getRRSet($old_record['name'], $old_record['type']);
@ -419,10 +478,14 @@ case "clone":
$srczone = new Zone();
$srczone->parse($api->loadzone($src));
if ($srczone->setSoaEditApi($defaults['soa_edit_api']) != False)
writelog("Set SOA-EDIT-API to ".$defaults['soa_edit_api']." for ",$srczone->name);
$srczone->setId('');
$srczone->setName($name);
$srczone->setSerial('');
$srczone->setKind($_POST['kind']);
$zone = $api->savezone($srczone->export());
$srczone->parse($zone);
@ -432,6 +495,15 @@ case "clone":
$newname = preg_replace('/'.$src.'$/', $name, $newname);
$rrset->setName($newname);
}
if (is_adminuser() && isset($_POST['account'])) {
add_db_zone($name, $_POST['account']);
$srczone->setAccount($_POST['account']);
} else {
add_db_zone($name, get_sess_user());
$srczone->setAccount(get_sess_user());
}
$zone = $api->savezone($srczone->export());
writelog("Cloned zone $src into $name");
@ -471,8 +543,11 @@ case "getformnameservers":
break;
case "formzonelist":
$zones = $api->listzones();
usort($zones, "zone_compare");
$ret = array();
foreach ($zones as $zone) {
if (!check_account($zone))
continue;
if ($zone['kind'] == 'Slave')
continue;
array_push($ret, array(
@ -488,4 +563,4 @@ default:
}
} catch (Exception $e) {
jtable_respond(null, 'error', $e->getMessage());
}
}