Compare commits

...

903 Commits
7.7 ... v8.3.1

Author SHA1 Message Date
Girish Ramakrishnan
f93462d88c 8.3.1 changes 2025-03-18 23:40:01 +01:00
Girish Ramakrishnan
e3982e48ea postgres: fix illegal instruction issue
we have to disable -march=native when compiling as per
https://github.com/pgvector/pgvector?tab=readme-ov-file#portability

https://github.com/pgvector/pgvector/issues/143
https://github.com/pgvector/pgvector/issues/752
https://github.com/pgvector/pgvector/issues/389
2025-03-18 23:38:40 +01:00
Girish Ramakrishnan
f77296bb2c update changelog for 8.3.0 2025-03-03 09:32:34 +01:00
Johannes Zellner
c0f7220040 Fix fs promise usage in sftp addon
(cherry picked from commit da8a7041d1)
2025-03-03 09:30:20 +01:00
Girish Ramakrishnan
d435b8b4e3 base image 5.0.0
(cherry picked from commit 3f3bb4d3b7)
2025-02-28 23:11:00 +01:00
Girish Ramakrishnan
c478ace8bd skip check when no ipv4/ipv6 2025-02-02 08:34:08 +01:00
Girish Ramakrishnan
5cfec4c371 remove duplicate inwx form fields 2025-02-02 07:30:19 +01:00
Girish Ramakrishnan
40cdf0c94d Update changelog 2025-02-01 09:19:16 +01:00
Girish Ramakrishnan
9908031b68 cloudflare: list recordrecord API does not return zone_id anymore
(cherry picked from commit 6c7341b9f3)
2025-02-01 09:17:12 +01:00
Girish Ramakrishnan
c5b48b4386 cloudron-support: auto cleanup
(cherry picked from commit 68066cdd48)
2025-02-01 09:16:59 +01:00
Girish Ramakrishnan
11fd3cafb5 const
(cherry picked from commit d1da77d6bc)
2025-02-01 09:16:44 +01:00
Girish Ramakrishnan
18dda10b54 remove usage of util.format
(cherry picked from commit 6cd97d2cb9)
2025-02-01 09:16:36 +01:00
Girish Ramakrishnan
1a73ddea23 req.connection.remoteAddress is deprecated
(cherry picked from commit 74f4849144)
2025-02-01 09:16:11 +01:00
Girish Ramakrishnan
f15b7dd75c username: only ending with .app is reserved
(cherry picked from commit b43fa38350)
2025-02-01 09:15:44 +01:00
Girish Ramakrishnan
51ed5b78f2 backups: add preserve attributes checkbox
(cherry picked from commit 837d5803c8)
2025-02-01 09:14:34 +01:00
Girish Ramakrishnan
fb2ec52464 update mail image
(cherry picked from commit 84a1f40115)
2025-02-01 09:13:42 +01:00
Girish Ramakrishnan
d158ba0464 mail: rebuild index
(cherry picked from commit abb40b3ad7)
2025-02-01 09:12:51 +01:00
Girish Ramakrishnan
b6b1eb2353 mail: disable ocr in tika
(cherry picked from commit dfd54b7b54)
2025-02-01 09:12:07 +01:00
Johannes Zellner
fd8eed048a Add inwx to dns setup
(cherry picked from commit 2ac3c1fe6e)
2025-02-01 09:11:13 +01:00
Girish Ramakrishnan
25ee2170f6 restore: fix crash with invalid backup id
(cherry picked from commit 230599417e)
2025-02-01 09:10:48 +01:00
Girish Ramakrishnan
c6641d23cd grammar
donald says so

(cherry picked from commit aaab06f21d)
2025-02-01 09:10:08 +01:00
Girish Ramakrishnan
f5f6b69d5d mail: add ipv6 rdns check
(cherry picked from commit 6fcfa6cac0)
2025-02-01 09:09:58 +01:00
Girish Ramakrishnan
e536c94028 firewall: add dockerproxy 2025-01-03 21:14:19 +01:00
Girish Ramakrishnan
d57020d269 firewall: allow udp responses to come back from docker 2025-01-03 19:50:42 +01:00
Girish Ramakrishnan
d47aa816d3 firewall: accept ldap connections 2025-01-03 19:33:51 +01:00
Girish Ramakrishnan
29a9b3d68a firewall: use a chain instead of adding rules directly
this helps in updating rules across upgrades
2025-01-03 17:59:24 +01:00
Girish Ramakrishnan
b6f70e4bc0 rsync: increase empty dir limit
a mail backup of a mailbox with many folders can have many empty dirs

https://forum.cloudron.io/topic/13047/since-update-to-v8-2-1-backups-fail-with-too-many-empty-directories
2025-01-03 13:01:10 +01:00
Girish Ramakrishnan
73e1e6881e docker: fix parsing of imageRef if no namespace 2025-01-03 10:10:06 +01:00
Girish Ramakrishnan
ebc3dfc3f0 mail: update the dns-list plugin 2025-01-03 09:36:11 +01:00
Girish Ramakrishnan
2ae05baec3 add to changelog 2025-01-02 23:53:00 +01:00
Girish Ramakrishnan
746bcb1dd0 firewall: ip6tables requires ipv6 2025-01-02 23:48:19 +01:00
Girish Ramakrishnan
874f8328b8 firewall: wait-interval is deprecated 2025-01-02 23:44:50 +01:00
Girish Ramakrishnan
62e2283992 firewall: add masquerade rule for access via public IP 2025-01-02 23:34:46 +01:00
Girish Ramakrishnan
0cf407b6f5 give mail container a static IP 2025-01-02 23:33:21 +01:00
Girish Ramakrishnan
8a97b7efa4 notifications: send unacked ones first 2025-01-02 16:50:31 +01:00
Girish Ramakrishnan
1e2ca7b835 volumes: test host path validation 2025-01-02 11:46:11 +01:00
Girish Ramakrishnan
f7ea847336 do not modify hostPath variable 2025-01-02 11:22:09 +01:00
Girish Ramakrishnan
9d890e1c21 security: fix issue where '/' symlink allows admins to get ssh access
* create a volume
* create symlink to /
* now, create another volume with that symlink as host directory
2025-01-02 11:18:39 +01:00
Girish Ramakrishnan
9c7e9e25ca scheduler: respect cloudron timezone setting 2025-01-02 10:11:14 +01:00
Girish Ramakrishnan
4ffe736d46 mail: dns list crash fix 2025-01-02 09:24:51 +01:00
Girish Ramakrishnan
13d82e5a4d mail: fix issue with dkim signing 2025-01-01 18:33:04 +01:00
Girish Ramakrishnan
a7f083dbd1 gandi: get token type in setup view 2025-01-01 15:43:46 +01:00
Girish Ramakrishnan
d3b82d68e7 add todo for ipv6 ptr 2024-12-22 12:39:33 +01:00
Girish Ramakrishnan
bd961025f6 platform: get shell output as utf8 2024-12-19 16:59:28 +01:00
Girish Ramakrishnan
c31da4eb2a add to changelog 2024-12-19 15:40:58 +01:00
Girish Ramakrishnan
812ecf4041 disable archiving for pre-8.2 backups
the sso situation complicates implementing restore for those
2024-12-19 15:31:07 +01:00
Girish Ramakrishnan
cd8be9ffb5 archive: appConfig is null for pre-8.2 backups
use backups.manifest when possible instead
2024-12-19 15:21:33 +01:00
Girish Ramakrishnan
40abb446d4 archive: disable button when busy 2024-12-19 15:13:20 +01:00
Johannes Zellner
96d740fb15 Use VITE_CACHE_ID also in index.js 2024-12-19 14:01:54 +01:00
Girish Ramakrishnan
5898436638 test: fix dockerproxy 2024-12-19 13:10:14 +01:00
Girish Ramakrishnan
17fee93002 apps: hide update indicator for normal users 2024-12-19 12:36:47 +01:00
Girish Ramakrishnan
68431ae357 rename functions to avoid mistakes
the remove fields are not clear enough. we sent notes by mistake to
normal users. changing the name and passing role as the argument
will avoid these errors
2024-12-19 12:24:08 +01:00
Girish Ramakrishnan
ba6ba44955 use enum for access levels 2024-12-19 12:24:08 +01:00
Girish Ramakrishnan
3b101a2086 remove spurious comment 2024-12-19 12:24:08 +01:00
Johannes Zellner
876fd218af Fix sso ordering in apps listing 2024-12-19 12:22:41 +01:00
Girish Ramakrishnan
cbd32e7372 apps: non-admins cannot see notes, checklist and enableBackup 2024-12-19 11:35:20 +01:00
Girish Ramakrishnan
324b82187b readme: reword some things 2024-12-19 10:32:30 +01:00
Girish Ramakrishnan
8d19c351e7 cloudron-support: add link to docs 2024-12-18 10:52:51 +01:00
Girish Ramakrishnan
5c00fb361a cloudron-support: suggest removing nodejs apt 2024-12-18 10:17:05 +01:00
Girish Ramakrishnan
903e0bc568 solr: show state correctly 2024-12-18 07:21:19 +01:00
Girish Ramakrishnan
d12a23b73f fts: enable and not enabled 2024-12-18 07:07:07 +01:00
Girish Ramakrishnan
6e34f84b14 Update fts translations 2024-12-17 21:19:29 +01:00
Girish Ramakrishnan
c74fa04b7f better text 2024-12-17 19:23:06 +01:00
Girish Ramakrishnan
758b05393c catch app backup error to release lock 2024-12-17 19:08:43 +01:00
Girish Ramakrishnan
219066d8d7 mail_templates: no format 2024-12-17 17:07:35 +01:00
Girish Ramakrishnan
449dd4730f archive: return the id in archive route 2024-12-17 14:33:36 +01:00
Girish Ramakrishnan
73ffe9ce41 link to App Archive 2024-12-17 11:34:53 +01:00
Girish Ramakrishnan
c21c24f088 Update translations 2024-12-17 11:01:12 +01:00
Girish Ramakrishnan
f35f548ecd mail: fix various upstream plugin changes 2024-12-16 23:57:56 +01:00
Girish Ramakrishnan
69d5283caf mail: use a lock to protect container recreation
needs a lock because the cert code also restart mail server from tasks
2024-12-16 22:34:52 +01:00
Girish Ramakrishnan
43950fc398 ldap: fix crash. function was renamed 2024-12-16 20:29:28 +01:00
Girish Ramakrishnan
d2e3b80517 taskworker: add debug 2024-12-16 15:17:35 +01:00
Girish Ramakrishnan
3728d8ecc1 porkbun: incorrect usage of promises 2024-12-16 14:07:03 +01:00
Girish Ramakrishnan
dcca524726 porkbun: timeout for all requests flat out 2024-12-16 10:03:16 +01:00
Girish Ramakrishnan
9ec5fc29aa dns: return same type 2024-12-16 09:55:54 +01:00
Girish Ramakrishnan
1d0f3a08f4 porkbun: it is really slow 2024-12-16 09:46:38 +01:00
Girish Ramakrishnan
3d8ffcd0f7 another typo 2024-12-14 23:28:00 +01:00
Girish Ramakrishnan
8c28871b76 typo 2024-12-14 23:25:14 +01:00
Girish Ramakrishnan
df53f827c5 release: happy eyeballs workaround 2024-12-14 22:00:45 +01:00
Girish Ramakrishnan
83adcd73a9 sqlite3: images.base is gone 2024-12-14 21:40:47 +01:00
Girish Ramakrishnan
8e6890b4d6 docker: rework image pruning
with our new retagging approach, the Digest ID remains <null> because
this is only set by docker if truly fetched from the registry.

this means that redis container always gets removed...
2024-12-14 20:47:35 +01:00
Girish Ramakrishnan
bd107e849b infra: no more images.base 2024-12-14 20:18:07 +01:00
Girish Ramakrishnan
5893f53b43 typo 2024-12-14 19:05:32 +01:00
Girish Ramakrishnan
1894ed7721 box: no oidc messages 2024-12-14 19:04:59 +01:00
Girish Ramakrishnan
96b715de8e apptask: try install via ipv4
our ci app images are not pushed to quay and the tests fail on
ipv6 servers
2024-12-14 18:55:55 +01:00
Girish Ramakrishnan
b26890f5b3 release: print the sourceEnv.url 2024-12-14 17:14:41 +01:00
Girish Ramakrishnan
5ae29eabaa docker: try ipv4 and then ipv6 explicitly
To get the ratelimits:
TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token)
curl --head -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest

docker appears to have some simple approach to track ipv6 limits.
2024-12-14 17:05:13 +01:00
Girish Ramakrishnan
d9e4aeb518 docker: replace pull with tag to not hit rate limits 2024-12-14 16:16:33 +01:00
Girish Ramakrishnan
6b7edbd552 docker: fallback to quay if docker hub does not work 2024-12-14 15:22:12 +01:00
Girish Ramakrishnan
12f19299a8 docker: only send credentials when registry matches 2024-12-14 14:21:15 +01:00
Girish Ramakrishnan
0008e5a83b docker: parse registry also 2024-12-14 14:10:29 +01:00
Girish Ramakrishnan
0bd1aac0ef refactor 2024-12-14 14:05:53 +01:00
Girish Ramakrishnan
5145344987 docker: do not use auth for cloudron namespace 2024-12-14 14:04:40 +01:00
Girish Ramakrishnan
cc980fbc0c add note on manifest id 2024-12-14 14:02:49 +01:00
Girish Ramakrishnan
878caff378 improve the comment 2024-12-14 14:01:38 +01:00
Girish Ramakrishnan
5ce82d6794 docker: parseImageRef 2024-12-14 14:00:05 +01:00
Girish Ramakrishnan
d456f91921 tasks: fix active status 2024-12-12 19:09:55 +01:00
Girish Ramakrishnan
3be77fc634 fix link 2024-12-12 15:21:05 +01:00
Girish Ramakrishnan
a4e68733ed use ttyUSB0 as placeholder 2024-12-12 12:33:54 +01:00
Johannes Zellner
eaae3f824b Also remove postinstall confirm checkbox from app view 2024-12-12 12:20:34 +01:00
Johannes Zellner
8d3b9685a1 Update postgres addon version 2024-12-12 12:01:57 +01:00
Johannes Zellner
3fa354a815 Update translations 2024-12-12 11:53:24 +01:00
Johannes Zellner
512722695e Fix archives for mobile 2024-12-12 11:52:59 +01:00
Johannes Zellner
9ed424a5d9 Add some changes 2024-12-12 11:22:15 +01:00
Johannes Zellner
a36ef67305 Update frontened dependencies 2024-12-12 11:19:38 +01:00
Girish Ramakrishnan
be340580d4 various notification fixes 2024-12-11 23:58:17 +01:00
Girish Ramakrishnan
fbe207dac3 typo 2024-12-11 23:01:00 +01:00
Girish Ramakrishnan
f59837f7c3 spurious console 2024-12-11 22:44:04 +01:00
Girish Ramakrishnan
d0d0913c70 notifications: add context field 2024-12-11 22:29:00 +01:00
Girish Ramakrishnan
701c25d07a notifications: add back app down and app oom mails 2024-12-11 20:56:15 +01:00
Johannes Zellner
d38b4d7b74 Fix notification setting button size and margin 2024-12-11 19:29:05 +01:00
Girish Ramakrishnan
8fd9324048 Fix crash 2024-12-11 19:17:44 +01:00
Girish Ramakrishnan
6004cd17bf notifications: per user email prefs 2024-12-11 19:12:20 +01:00
Girish Ramakrishnan
746e694d7e notifications: rename alert to pin and unpin 2024-12-11 17:31:32 +01:00
Girish Ramakrishnan
ead419003b notifications: rename ALERT_ to TYPE_ 2024-12-11 15:29:20 +01:00
Girish Ramakrishnan
6141db8f34 Update ubuntu check to bionic 2024-12-11 15:03:59 +01:00
Girish Ramakrishnan
6993cbeb9f archive: download the config 2024-12-11 10:54:51 +01:00
Girish Ramakrishnan
96f2c6e2aa archive: add button to download the config 2024-12-11 09:50:54 +01:00
Girish Ramakrishnan
65f507bc75 clone: read custom icon from downloaded backup
the backups table does not have icon to save space. only the
archives table has it for the moment.
2024-12-10 22:47:21 +01:00
Girish Ramakrishnan
05d6484d27 clone: label should be from dolly 2024-12-10 21:07:59 +01:00
Girish Ramakrishnan
41bc08a07e backup: move appConfig to backups table
this is useful for clone also to copy notes, operators, checklist
of the time when the backup was made (as opposed to current)

at this point, it's not clear why we need a archives table. it's
an optimization to not have to store icon for every backup.
2024-12-10 21:04:37 +01:00
Girish Ramakrishnan
98058f600e archive: prefill secondary domain correctly 2024-12-10 19:27:19 +01:00
Girish Ramakrishnan
41b302b0b9 apps: unarchive can call add() on it's own
all this because the sso flag is not allowed with optionalSso :/
2024-12-10 19:09:29 +01:00
Girish Ramakrishnan
fbe334e7d7 install/unarchive: add support for various fields 2024-12-10 18:39:16 +01:00
Girish Ramakrishnan
9a155491cb move unarchive to apps model 2024-12-10 17:19:12 +01:00
Girish Ramakrishnan
ab8ec07f2f clone/unarchive: handle notes and checklist 2024-12-10 17:16:06 +01:00
Girish Ramakrishnan
3e1c886b17 clone: copy devices 2024-12-10 16:49:25 +01:00
Girish Ramakrishnan
21c3d16db5 archive: proxy app cannot be archived 2024-12-10 16:49:25 +01:00
Girish Ramakrishnan
0e181cdc82 archive: implement unarchive
made a separate route instead of reusing install route. this was
because we want to copy over all the old app config as much as
possible.
2024-12-10 16:49:19 +01:00
Girish Ramakrishnan
e168be6d97 appstore: remove traces of custom cert 2024-12-10 14:49:54 +01:00
Girish Ramakrishnan
f65be99017 appstore: remove ununsed cert input 2024-12-10 14:47:00 +01:00
Girish Ramakrishnan
e201d4c896 archive: add confirm delete dialog 2024-12-10 14:26:07 +01:00
Johannes Zellner
a8035d01c6 Fix archive app icons 2024-12-10 13:25:44 +01:00
Johannes Zellner
054275f143 appstore id tooltip should be on the string not the table cell 2024-12-10 13:15:09 +01:00
Johannes Zellner
e652456d54 vertically align action buttons in archive table 2024-12-10 13:04:57 +01:00
Johannes Zellner
1e6a7d72ab Attach tooltip to body to not break table layout 2024-12-10 13:02:31 +01:00
Johannes Zellner
965054a707 Fix translation typo 2024-12-10 12:58:22 +01:00
Johannes Zellner
9a26dc090e Allow to set DASHBOARD_DEVELOPMENT_ORIGIN in env for local development 2024-12-10 12:56:09 +01:00
Girish Ramakrishnan
30b0d4cced archives: add listing 2024-12-10 12:30:10 +01:00
Girish Ramakrishnan
f973536f7f archives: add eventlog 2024-12-10 11:10:35 +01:00
Girish Ramakrishnan
490840b71d archives: use separate table
Cleaner to separate things from the backups table.

* icon, appConfig, appStoreIcon etc are only valid for archives
* older version cloudron does not have appConfig in backups table (so it
  cannot be an archive entry)
2024-12-10 10:36:44 +01:00
Girish Ramakrishnan
2ad93c114e archive: add appConfig, icon and appStoreIcon 2024-12-09 23:25:31 +01:00
Girish Ramakrishnan
cec2106cfe update the schema file 2024-12-09 22:42:22 +01:00
Girish Ramakrishnan
9200e6fc63 add archives api 2024-12-09 22:39:28 +01:00
Girish Ramakrishnan
5907975c02 remove App from start/stop/restart 2024-12-09 21:26:35 +01:00
Girish Ramakrishnan
fe68887cdd archive: add confirm dialog 2024-12-09 21:22:06 +01:00
Girish Ramakrishnan
24df6edbf1 update archive translations 2024-12-09 19:14:33 +01:00
Girish Ramakrishnan
710bd270d7 apps: add archive action 2024-12-09 18:51:49 +01:00
Girish Ramakrishnan
147e014205 backup: add archive flag 2024-12-09 16:25:31 +01:00
Girish Ramakrishnan
65a7f5f1c6 Use subarray instead of slice
says it's deprecated
2024-12-09 16:14:49 +01:00
Girish Ramakrishnan
cfc3a4217d platform: mark apps early
this gives some UI feedback when the platform is starting
2024-12-09 15:04:14 +01:00
Girish Ramakrishnan
35be854997 apptaskmanager: do not schedule tasks until infra ready 2024-12-09 14:46:03 +01:00
Johannes Zellner
58af890abe Do not crash on assert if backup task failed 2024-12-09 13:09:51 +01:00
Girish Ramakrishnan
ada878c939 hetzner: add helsinki object storage location 2024-12-09 09:44:35 +01:00
Girish Ramakrishnan
08435fbe26 release: more debugs 2024-12-09 09:06:38 +01:00
Girish Ramakrishnan
00a643e70a release: add the env.tag to output 2024-12-09 09:03:36 +01:00
Girish Ramakrishnan
cc759a8427 Add waiting for lock message 2024-12-09 08:40:54 +01:00
Girish Ramakrishnan
bb392207ea remove global lock
Currently, the update/apptask/fullbackup/platformstart take a
global lock and cannot run in parallel. This causes situations
where when a user tries to trigger an apptask, it says "waiting for
backup to finish..." etc

The solution is to let them run in parallel. We need a lock at the
app level as app operations running in parallel would be bad (tm).
In addition, the update task needs a lock just for the update part.
We also need multi-process locks. Running tasks as processes is core
to our "kill" strategy.

Various inter process locks were explored:

* node's IPC mechanism with process.send(). But this only works for direct node.js
children. taskworker is run via sudo and the IPC does not work.

* File lock using O_EXCL. Basic ideas to create lock files. While file creation
can be done atomically, it becomes complicated to clean up lock files when
the tasks crash. We need a way to know what locks were held by the crashing task.
flock and friends are not built-into node.js

* sqlite/redis were options but introduce additional deps

* Settled on MySQL based locking. Initial plan was to have row locks
or table locks. Each row is a kind of lock. While implementing, it was found that
we need many types of locks (and not just update lock and app locks). For example,
we need locks for each task type, so that only one task type is active at a time.

* Instead of rows, we can just lock table and have a json blob in it. This hit a road
block that LOCK TABLE is per session and our db layer cannot handle this easily! i.e
when issing two db.query() it might use two different connections from the pool. We have to
expose the connection, release connection etc.

* Next idea was atomic blob update of the blob checking if old blob was same. This approach,
was finally refined into a version field.

Phew!
2024-12-07 20:41:22 +01:00
Girish Ramakrishnan
a5b9ff0c3a add to changelog 2024-12-07 11:27:52 +01:00
Johannes Zellner
146afce934 Improve devices error handling 2024-12-06 13:35:52 +01:00
Girish Ramakrishnan
de0909248d start.sh: collapse the mkdir lines 2024-12-05 15:53:03 +01:00
Johannes Zellner
d5b3a56129 dashboard: show devices error within the form 2024-12-05 15:27:10 +01:00
Johannes Zellner
fbed850acc Also validate devices in the setter route 2024-12-05 15:16:06 +01:00
Johannes Zellner
25fb467c02 dashboard: initial UI to attach devices to apps 2024-12-05 14:49:36 +01:00
Johannes Zellner
8493022f75 Allow apps to specify custom devices 2024-12-05 14:21:07 +01:00
Johannes Zellner
621c1ed95a dashboard: import momentjs with all locales 2024-12-05 12:19:58 +01:00
Johannes Zellner
4992e284fb dashboard: never hide or wrap action buttons in app list 2024-12-04 18:15:34 +01:00
Girish Ramakrishnan
e4fb040ddf make tests great again 2024-12-04 16:36:05 +01:00
Girish Ramakrishnan
2bfa49cc2e applinks: add tests 2024-12-04 16:17:07 +01:00
Girish Ramakrishnan
3b9d617e37 groups: add events to eventlog 2024-12-04 11:30:30 +01:00
Girish Ramakrishnan
fdf8025a02 style: remove -> del 2024-12-03 17:36:50 +01:00
Girish Ramakrishnan
423dfb6ace schema: update comment 2024-12-03 16:33:59 +01:00
Girish Ramakrishnan
0a4aede3a8 eventlog: branding events 2024-12-02 12:18:09 +01:00
Girish Ramakrishnan
872705d58d oidc: use the cloudron name as provider name 2024-12-02 12:01:19 +01:00
Girish Ramakrishnan
ca5776e6f3 services: fix oidc usage 2024-12-02 11:00:12 +01:00
Girish Ramakrishnan
d4998b5d55 rename view user-settings to user-directory 2024-12-02 09:02:58 +01:00
Girish Ramakrishnan
e93f5e3e87 oidc: show name in delete dialog 2024-12-02 08:56:03 +01:00
Girish Ramakrishnan
d29bb90c5a update various oidc translations 2024-12-02 08:56:03 +01:00
Girish Ramakrishnan
1230e5c9e7 oidc: add load pattern 2024-12-02 08:36:03 +01:00
Girish Ramakrishnan
dc3d23c27b oidc: flatten the export list 2024-12-02 08:31:35 +01:00
Girish Ramakrishnan
6623061c2c services: fix ticks 2024-11-30 18:02:29 +01:00
Girish Ramakrishnan
1ecb853309 mail: attachment search 2024-11-30 17:42:26 +01:00
Girish Ramakrishnan
2a6c52800b system: filesystems in exclude are excluded from content analysis
some disks can be very slow and noisy (at home). this allows users to simply skip them.
also, applicable for large storage boxes
2024-11-30 13:08:21 +01:00
Girish Ramakrishnan
320ddfda2e compute docker df only once 2024-11-30 12:44:15 +01:00
Girish Ramakrishnan
40febc8ef2 system: rename DISK_TYPES to FS_TYPES 2024-11-30 12:04:07 +01:00
Girish Ramakrishnan
56f6519b3e rename disks to filesystems 2024-11-30 12:04:04 +01:00
Girish Ramakrishnan
f219abf082 system: indent cache file 2024-11-30 11:11:54 +01:00
Girish Ramakrishnan
742a04d149 system: expose getDisks only for tests 2024-11-30 10:42:06 +01:00
Girish Ramakrishnan
26caacc12e Fix debugs 2024-11-30 10:18:48 +01:00
Girish Ramakrishnan
1497518867 better assert message 2024-11-30 10:18:40 +01:00
Johannes Zellner
1a4a69f365 update postgres to add pgvector extension 2024-11-28 17:37:22 +01:00
Girish Ramakrishnan
78520e09c3 domains: add inwx provider 2024-11-26 19:13:33 +05:30
Girish Ramakrishnan
f0207ff161 test: comment it out, it is not run anyway 2024-11-26 15:54:55 +05:30
Girish Ramakrishnan
dd45f1c032 cloudron-support: set connect timeout and redirect ping output 2024-11-26 11:15:27 +05:30
Girish Ramakrishnan
ddf1c8e385 cloudron-support: clarify ipv6 in kernel 2024-11-26 11:10:58 +05:30
Girish Ramakrishnan
948efbaa76 docker: upgrade docker to 27.3.1 2024-11-23 20:31:44 +05:30
Girish Ramakrishnan
ccd1a4319d lint 2024-11-21 19:18:26 +05:30
Girish Ramakrishnan
22be1f1b72 sqlite: create dumps based on the basename 2024-11-21 12:34:06 +05:30
Girish Ramakrishnan
7095862601 sqlite: add some comments 2024-11-21 12:24:27 +05:30
Girish Ramakrishnan
fa98e0570f sqlite: change path to paths 2024-11-21 10:02:26 +05:30
Girish Ramakrishnan
4316d3eade add sqlite3 addon take 2
- there is no container id during the addon lifecycle
- sqlite3 requires the localstorage addon to be inited. so this has to
  become like the ftp option
- remove all that child_process streaming stuff. too complicated
2024-11-21 00:13:17 +05:30
Girish Ramakrishnan
f8cd0b5f52 add sqlite3 addon 2024-11-21 00:13:17 +05:30
Girish Ramakrishnan
a8b3f69acc Update manifestformat 2024-11-21 00:13:17 +05:30
Johannes Zellner
78cb36ea0e Start using POST /api/v1/apps to install 2024-11-20 16:18:37 +01:00
Girish Ramakrishnan
b4d58f0609 aws: add a 20min timeout
in some services like b2, the multi-part copy just hangs. this allows
us to retry
2024-11-20 07:13:43 +05:30
Girish Ramakrishnan
18abc214a6 mail: update haraka to 3.0.5 2024-11-20 06:32:13 +05:30
Girish Ramakrishnan
5e3857fd3d Fix assert
NETWORK_ERROR is usually an AggregateError which causes an
assert in BoxError
2024-11-19 17:08:55 +05:30
Johannes Zellner
e35b36643c Add more oidc debugs 2024-11-18 18:09:01 +01:00
Johannes Zellner
16fa339025 Add refresh_token grant type 2024-11-18 18:07:32 +01:00
Girish Ramakrishnan
051b0e0fd3 oidc: set a refresh token ttl to avoid warning
oidc-provider NOTICE: default ttl.RefreshToken function called, you SHOULD change it in order to define the expiration for RefreshToken artifacts.
2024-11-18 15:29:14 +05:30
Girish Ramakrishnan
62d3212f88 applink: add timeout when detecting metadata 2024-11-18 08:18:39 +05:30
Girish Ramakrishnan
fd96665e97 rsync: show better error message with too many empty dirs, symlinks or executables 2024-11-18 08:11:14 +05:30
Girish Ramakrishnan
8f6637773b shell: add option for maxLines 2024-11-18 07:59:05 +05:30
Girish Ramakrishnan
d7f829b3e1 Fix link 2024-11-10 09:35:42 +01:00
Johannes Zellner
3fdb43762b Do not make app dockerImage overflow 2024-11-08 21:39:44 +01:00
Girish Ramakrishnan
7ae02a62fe quote the filename 2024-11-08 21:11:23 +01:00
Johannes Zellner
11cb33fe25 Update dashboard dependencies 2024-11-08 18:33:44 +01:00
Johannes Zellner
a09202d1fa Show some error in filemanager if pasting fails 2024-11-08 18:28:57 +01:00
Johannes Zellner
fcccccaaae Ask for app restart confirmation 2024-11-08 18:15:34 +01:00
Johannes Zellner
9f80578bab Avoid preview flickering for psd image files 2024-11-08 18:15:34 +01:00
Girish Ramakrishnan
32e3665b7a more changes 2024-11-08 17:15:40 +01:00
Girish Ramakrishnan
e9c10b306c update translations 2024-11-08 17:15:40 +01:00
Johannes Zellner
dabadcc00e Ensure minimum flexitem width for disk usage 2024-11-08 16:48:40 +01:00
Girish Ramakrishnan
9cc594d633 hetzner: add nbg1 2024-11-08 16:21:25 +01:00
Girish Ramakrishnan
8350eeb751 cloudron-support: rename enable-remote-access to enable-remote-support 2024-11-08 16:01:30 +01:00
Johannes Zellner
7b61bafab7 Fix oidc login layout for long instance names 2024-11-06 17:15:03 +01:00
Girish Ramakrishnan
6407d795ed du: better error handling of du
du can fail when files and directories go missing. luckily, when du fails,
it still provides the best effort output
2024-11-06 14:54:52 +01:00
Girish Ramakrishnan
9cf235af39 boxerror: assign extra fields in all cases 2024-11-06 13:40:37 +01:00
Johannes Zellner
18e5365104 Fix typo 2024-11-05 14:24:40 +01:00
Johannes Zellner
c03eff8da2 shell.js using argument array list now 2024-11-05 13:09:27 +01:00
Johannes Zellner
28f79cd6c9 return early if docker ps returns nothing 2024-11-05 13:05:12 +01:00
Girish Ramakrishnan
fc2786b07f taskworker: fix programming error 2024-11-01 16:15:32 +01:00
Johannes Zellner
620ad13427 Add more changes 2024-11-01 16:03:19 +01:00
Johannes Zellner
0776442a5f Silence deprecation warning caused by old bootstrap import 2024-10-31 10:29:37 +01:00
Girish Ramakrishnan
4a207395ca middleground in timeout
DO BLR droplets still fail with 1s timeout!
2024-10-31 10:22:55 +01:00
Girish Ramakrishnan
2df983a1cf lower timeout 2024-10-31 09:50:20 +01:00
Girish Ramakrishnan
03e17aea22 taskworker: refactor 2024-10-31 09:46:36 +01:00
Girish Ramakrishnan
aefa481c43 network: fix premature connection closures with node 20 and above
the happy eyeballs implementation in node is buggy. ipv4 and ipv6 connections
are made in parallel and whichever responds first is chosen. when there is no
ipv6 (immediately errors with ENETUNREACH/EHOSTUNREACH) and when ipv4 is > 250ms,
the code erroneously times out.

see also https://github.com/nodejs/node/issues/54359

reproduction for those servers:

const options = {
  hostname: 'www.cloudron.io', port: 80, path: '/', method: 'HEAD',
  // family: 4, // uncomment to make it work
};

const req = require('http').request(options, (res) => {
  console.log('statusCode:', res.statusCode);
  res.on('data', () => {}); // drain
});

req.on('socket', (socket) => console.log('Socket assigned to request', socket););
req.on('error', (e) => console.error(e));
req.end();
2024-10-31 09:38:40 +01:00
Girish Ramakrishnan
553c256d31 better debugs 2024-10-30 20:58:37 +01:00
Johannes Zellner
b6023afb29 Silence most dashboard sass deprecation warnings 2024-10-30 19:29:24 +01:00
Girish Ramakrishnan
0df1e3a47f appstore: networkError is an aggreate error 2024-10-30 18:30:53 +01:00
Girish Ramakrishnan
78a08c5a0b Use a real string as second argument since message can be undefined 2024-10-30 17:59:55 +01:00
Girish Ramakrishnan
55a880c9ac Fix typo
14a18a42b7
2024-10-30 17:41:57 +01:00
Girish Ramakrishnan
61341b8380 boxerror: always pass second error string 2024-10-30 17:32:12 +01:00
Girish Ramakrishnan
a32b567eb1 boxerror: remove unused override 2024-10-30 15:43:53 +01:00
Johannes Zellner
25462d3290 pankow support dropdown buttons so use that in filemanager 2024-10-30 13:05:24 +01:00
Johannes Zellner
a9207b392b Folder creation is a query arg not body param 2024-10-30 13:01:26 +01:00
Johannes Zellner
c0f3c3bd2b dashboard: update dependencies 2024-10-30 12:28:07 +01:00
Johannes Zellner
8621fbda79 Enable refresh tokens for oidc provider 2024-10-29 16:20:53 +01:00
Johannes Zellner
84de986efd Network mounts should only depend on systemd network-online.target now 2024-10-29 14:07:03 +01:00
Girish Ramakrishnan
0f3ab11532 Update node to 20.18.0
We need https://nodejs.org/dist/latest-v20.x/docs/api/cli.html#--network-family-autoselection-attempt-timeout

The happy eyeballs implementation in node is buggy - https://github.com/nodejs/node/issues/54359
2024-10-28 09:55:54 +01:00
Johannes Zellner
6b4a81e471 dashboard: bring back cache busting for old script included assets 2024-10-27 12:10:00 +01:00
Johannes Zellner
14a18a42b7 Avoid crash in externalldap if search result has no username 2024-10-22 14:49:14 +02:00
Johannes Zellner
2c28eddc2b Fix linter errors 2024-10-22 14:40:53 +02:00
Girish Ramakrishnan
1b22ea661c avatar: deliver .png images
this is required for mastodon atleast. if the oidc avatar url, returns
an svg, it crashes!

the profile pic png was created using inkspace:
inkscape -w 96 -h 96 avatar-default-symbolic.svg -o avatar-default-symbolic.png
2024-10-18 22:39:18 +02:00
Girish Ramakrishnan
efc3c7532e Move requires to the top 2024-10-18 21:50:38 +02:00
Johannes Zellner
a3a807f22c Ensure we stick to dark background in dark mode 2024-10-18 18:33:38 +02:00
Johannes Zellner
fac5d3c07b Add code for cloudron-support to check and fix docker version 2024-10-17 12:41:33 +02:00
Girish Ramakrishnan
df5ba25010 shell: add explicit bash() function 2024-10-16 10:40:17 +02:00
Johannes Zellner
d66db8ca40 Use the correct new redis image 2024-10-15 22:28:52 +02:00
Johannes Zellner
0722d7ceb9 Update redis addon to set memory policy to noeviction 2024-10-15 22:07:17 +02:00
Johannes Zellner
06a23951c9 Use flexbox for sysinfo layout 2024-10-15 19:49:17 +02:00
Johannes Zellner
727d4876f5 Mobile fixes for volumes 2024-10-15 19:35:24 +02:00
Johannes Zellner
f5a43786c2 Fix mobile view for services 2024-10-15 19:24:05 +02:00
Johannes Zellner
30967af8ec Fixup most mobile issues for eventlog 2024-10-15 19:19:16 +02:00
Johannes Zellner
ccd892708b Hide wide summary for mail domains on mobile 2024-10-15 18:56:36 +02:00
Johannes Zellner
8cf3e38b27 Rework all section headers to deal with mobile wrapping 2024-10-15 18:46:51 +02:00
Johannes Zellner
4685f42045 fixup backups view for mobile 2024-10-15 17:50:46 +02:00
Johannes Zellner
e6232189e7 use flexbox for appstore toolbar 2024-10-15 17:47:59 +02:00
Johannes Zellner
6e12d06343 Use flexbox for profile panel instead of old boostrap grid 2024-10-15 17:27:58 +02:00
Johannes Zellner
d02b6d90cc Update translation 2024-10-15 15:51:27 +02:00
Johannes Zellner
d10e9d7098 Fix api token list on mobile 2024-10-15 15:31:45 +02:00
Johannes Zellner
57b0cca6ab Give headers more space on mobile 2024-10-15 15:26:10 +02:00
Johannes Zellner
fc565fd818 Give mobile navbar menu a shadow to elevate it from the content 2024-10-15 14:41:10 +02:00
Johannes Zellner
4e0c439c6f Close navbar in mobile if item is selected 2024-10-15 13:16:50 +02:00
Johannes Zellner
39220ba408 Do not remove all card padding on mobile 2024-10-15 13:05:33 +02:00
Girish Ramakrishnan
7fbb9f9df3 remove explicit encoding 2024-10-15 12:23:32 +02:00
Girish Ramakrishnan
6c3ca9c364 shell: rework code to use shell.spawn
spawn gives out streams and we have more control over the stdout/stderr
buffers. otherwise, we have to provide a max buffer capture size to exec
2024-10-15 12:13:46 +02:00
Girish Ramakrishnan
7b648cddfd shell: direct exports not needed anymore 2024-10-15 09:26:02 +02:00
Girish Ramakrishnan
a9e1d7641d shell: make require take a tag 2024-10-14 21:08:32 +02:00
Girish Ramakrishnan
02823c4158 test: use same dashboard dir 2024-10-14 19:03:52 +02:00
Girish Ramakrishnan
d58789cc25 test: more test fixing 2024-10-14 18:37:22 +02:00
Girish Ramakrishnan
434a0cba9f test: translation path has changed 2024-10-14 18:33:04 +02:00
Girish Ramakrishnan
ca8695a1d3 typo 2024-10-14 18:26:16 +02:00
Girish Ramakrishnan
7f141605fa log the backuptask crash reason 2024-10-14 18:26:01 +02:00
Girish Ramakrishnan
23f9b5f2fc logs: when no timestamp, use the last known 2024-10-14 16:30:30 +02:00
Girish Ramakrishnan
1abbe43785 log exception with timestamp prefixed 2024-10-14 16:21:25 +02:00
Girish Ramakrishnan
6361737cf4 sudo: use debug() to have provide timestamped logs
the exception is when sudo calls backupupload.js which already has timestamped
output because it uses node

an alternative idea is to maybe not use this flag at all and always parse the output.
this is a bit complicated since we have to look for a timestamp in a stream.
2024-10-14 15:38:55 +02:00
Girish Ramakrishnan
a884f968e1 syslog: fix parsing of multi-message packets 2024-10-14 13:54:32 +02:00
Johannes Zellner
ce611c4773 dashboard: only open the cloudron detail page to create a subscription 2024-10-12 18:52:49 +02:00
Girish Ramakrishnan
ba75c7ddaa porkbun: api endpoint has changed
https://porkbun.com/api/json/v3/documentation
2024-10-12 10:58:21 +02:00
Girish Ramakrishnan
ff5dccc2b4 remove obsolete comment 2024-10-12 10:50:58 +02:00
Johannes Zellner
9b8994fe43 dashboard: fix changing views from appstore view after installation 2024-10-11 11:28:08 +02:00
Girish Ramakrishnan
34969d9980 groups: bump group_concat_max_len to accomdate more users 2024-10-09 19:12:53 +02:00
Johannes Zellner
da11e90333 Static busy spinner for oidc login views 2024-10-09 13:14:43 +02:00
Johannes Zellner
282d06404e Static assets are actually on / 2024-10-09 12:56:25 +02:00
Johannes Zellner
64e60c106b Produce a static theme.css for oidc login views 2024-10-09 12:52:22 +02:00
Johannes Zellner
1b3fd20755 Fixup oidc pages to match new location of dashboard assets 2024-10-09 11:31:02 +02:00
Girish Ramakrishnan
ce5a2b1f0a gandi: use PAT token instead
https://api.gandi.net/docs/authentication/
2024-10-08 17:51:01 +02:00
Johannes Zellner
d68d5d5c51 Since dashboard is of type module we need to add correct common js extensions 2024-10-08 17:23:52 +02:00
Johannes Zellner
5a3460efb7 mimer.js is not used at all 2024-10-07 20:54:08 +02:00
Johannes Zellner
edf5ddf027 Remove not required autofill polyfill 2024-10-07 20:50:01 +02:00
Johannes Zellner
982714fa4c We are not exporting this via git or so 2024-10-07 20:42:32 +02:00
Johannes Zellner
90ee525be7 Remove old unused dashboard scripts 2024-10-07 20:41:37 +02:00
Johannes Zellner
600323e027 Remove unused bootstrap files 2024-10-07 20:37:53 +02:00
Johannes Zellner
46a8b59196 Fixup mobile view for app list 2024-10-07 16:53:31 +02:00
Johannes Zellner
f96ae1a1de mobile fixes for search and filter bar 2024-10-07 16:48:31 +02:00
Johannes Zellner
8894ec3019 Fix navbar menu with background set 2024-10-07 16:05:25 +02:00
Johannes Zellner
6f914a8d6b Handle scss files with vite also 2024-10-07 14:56:49 +02:00
Johannes Zellner
9f06b91399 Merge remaining frontend into dashboard 2024-10-04 21:37:17 +02:00
Johannes Zellner
9d7f12952d Move terminal.html to dashboard 2024-10-04 21:04:08 +02:00
Johannes Zellner
bc4e6ab1de Move logs.html from frontend to dashboard 2024-10-04 20:47:49 +02:00
Johannes Zellner
2300e1baee Fully replace gulp with vite 2024-10-04 17:43:45 +02:00
Johannes Zellner
1b00e0f254 Multiselect now works with vite 2024-10-04 16:38:36 +02:00
Johannes Zellner
6534e99103 Make it possible to use a dynamic api endpoint for local development 2024-10-04 15:22:11 +02:00
Johannes Zellner
ac98895e15 noto font is imported as module 2024-10-04 15:14:58 +02:00
Johannes Zellner
4e0961ae5a Translation files are now in public/ 2024-10-04 15:06:30 +02:00
Johannes Zellner
7669b77069 Some cleanup 2024-10-04 15:01:32 +02:00
Johannes Zellner
529d5b0b7b We use chartjs directly 2024-10-04 14:51:22 +02:00
Johannes Zellner
6edc482aad We don't target very old browsers anymore 2024-10-04 14:49:49 +02:00
Johannes Zellner
8fce81a264 Initial vite support for dashboard 2024-10-04 14:30:44 +02:00
Girish Ramakrishnan
ea2479beda system: also get rota information 2024-09-30 14:09:15 +02:00
Johannes Zellner
40e7ee91d7 filemanager: fix new folder api call 2024-09-28 20:27:59 +02:00
Johannes Zellner
813942edbd Update frontend dependencies 2024-09-28 20:15:09 +02:00
Girish Ramakrishnan
b70747de6f Add Cloudron Container Registry as option 2024-09-26 20:35:28 +02:00
Johannes Zellner
1c58f9aa5a dashboard: another small padding fix 2024-09-25 21:36:37 +02:00
Johannes Zellner
93aa2a4e6e dashboard: Better view-header padding 2024-09-25 17:26:43 +02:00
Girish Ramakrishnan
0504e0423a backups: add hetzner object storage 2024-09-25 12:21:42 +02:00
Girish Ramakrishnan
c1c16ab54e test: add simple gitlab-ci file 2024-09-20 18:48:55 +02:00
Girish Ramakrishnan
76dc856dbf test: fix system test 2024-09-20 15:37:34 +02:00
Vladimir D
227fdf10dd OIDC: id_token added to client response types 2024-09-20 14:16:40 +02:00
Girish Ramakrishnan
19c744b17d unbound-anchor is now part of ExecStartPre
it seems unbound-anchor is not a dep of unbound in ubuntu 24. some
installations are thus missing this package.

in any case, ignore unbound-anchor exit status
2024-09-20 10:00:01 +02:00
Vladimir D
3ce74d04d0 OIDC: groups claim added to make groups provisioned 2024-09-19 13:08:20 +02:00
Johannes Zellner
87b8fc6a1b dashboard: remove box-shadow on form-controls to be inline with buttons 2024-09-19 13:04:03 +02:00
Johannes Zellner
9012badfb8 dashbaord: Fix form-control align in filter bars 2024-09-19 12:19:09 +02:00
Girish Ramakrishnan
3b6e5d8ed1 cloudron-support: ipv6 checks 2024-09-19 12:11:56 +02:00
Girish Ramakrishnan
1148724613 boxerror: handle AggregateError 2024-09-19 11:44:47 +02:00
Girish Ramakrishnan
f526695aae cloudron-support: enable-ssh has an alias enable-remote-support 2024-09-19 08:38:59 +02:00
Girish Ramakrishnan
e8850eeac2 8.0.6 changelog 2024-09-18 15:33:42 +02:00
Girish Ramakrishnan
777834d790 dig: set tries parameter 2024-09-18 15:25:48 +02:00
Girish Ramakrishnan
dca9246450 Fix AdGuard resolving dashboard to docker bridge IP
Issue 1: DO droplet when given the name my.blah.com , will put an entry
in /etc/hosts with `127.0.1.1 my.blah.com` . When app containers use
system DNS, they get this IP address which does not work inside a container.

An idea is to remove this entry when running cloudron-setup, but maybe this
causes trouble later.

Issue 2: Some networks seem to lack loopback networking. With OIDC changes,
we want the apps to access my.blah.com even if hairpin nat is not working.

Solution: make my.blah.com to resolve to the docker bridge IP (172.18.0.1)
where nginx also listens to. This means that such requests never go outside the server

Caveats:
* This breaks AdGuard which now starts resolving it to 172.18.0.1 for
the entire network! So, we skip ExtraHosts configuration for adguard

* Maybe ExtraHosts should be scoped to OIDC apps only. But the thought here is
that it will help apps like say n8n which are querying dasahboard.
2024-09-18 14:42:11 +02:00
Girish Ramakrishnan
767f7ab40e capitalize view name 2024-09-18 13:10:26 +02:00
Johannes Zellner
1b810ec74f Only add unchecked checklist items on fresh installs for the moment 2024-09-16 13:46:19 +02:00
Johannes Zellner
f59b9e1b5f frontend: adjust filemanager to new pankow api 2024-09-16 13:28:30 +02:00
Johannes Zellner
398dbe802e frontend: remove another unused css rule 2024-09-16 12:21:14 +02:00
Johannes Zellner
8b5fa0fe76 frontend: purge unwanted css styles 2024-09-16 12:08:10 +02:00
Johannes Zellner
99042a47f3 frontend: Fix all toolbuttons 2024-09-16 12:05:41 +02:00
Johannes Zellner
46e600abe9 frontend: fixup LogsViewer 2024-09-16 11:50:20 +02:00
Johannes Zellner
051dd8b58f frontend: update dependencies 2024-09-16 11:50:20 +02:00
Girish Ramakrishnan
067b02dba1 dashboard: reconfigure all apps on location change
continuation of 1b5fee233e

all containers have ExtraHosts , so we have to reconfigure everything
2024-09-16 11:23:06 +02:00
Girish Ramakrishnan
22a0874188 grammar 2024-09-16 10:37:01 +02:00
Girish Ramakrishnan
0e25809158 settings: do not overflow the schedule 2024-09-16 10:29:35 +02:00
Girish Ramakrishnan
305d877896 operator: fix resource view
app resources view requires the cpu and memory information
2024-09-13 16:47:13 +02:00
Girish Ramakrishnan
a932a5251a update: all operators to update an app
previously, the update info was restricted to admins. this can now be queried
by any authenticated user. update information can be gathered from listing apps and
then checking against appstore anyway.
2024-09-13 16:46:58 +02:00
Girish Ramakrishnan
7b58fccb9f app info: fix overflow of manifest id 2024-09-13 11:34:30 +02:00
Johannes Zellner
859fef62d4 Revert "Make unbound prefer ipv4 to avoid using ipv6 for spam checking"
This reverts commit aedf55dba0.
2024-09-12 17:41:12 +02:00
Girish Ramakrishnan
0647a3a233 unbound: prefer ip4 on ubuntu 24 and above
ip6 queries seems to be blocked by spamhaus
2024-09-12 17:13:50 +02:00
Johannes Zellner
aedf55dba0 Make unbound prefer ipv4 to avoid using ipv6 for spam checking 2024-09-12 16:43:34 +02:00
Girish Ramakrishnan
e9a422b657 logs: handle logs not found (logrotated)
we show an error message in the UI now
2024-09-12 10:32:00 +02:00
Girish Ramakrishnan
23df6bdfbf add to changes 2024-09-11 17:55:35 +02:00
Girish Ramakrishnan
1b5fee233e docker: use the system dns for app containers
take 2 after failed attempt with 92bce26e22

this makes the dashboard domain resolve internally to nginx

can test with `getent ahosts my.domain.com` inside the container.
2024-09-11 17:52:25 +02:00
Girish Ramakrishnan
63457d2de4 Revert "docker: use the system dns for app containers"
This reverts commit 92bce26e22.
2024-09-10 19:37:39 +02:00
Girish Ramakrishnan
732c944e98 changelog: update release version 2024-09-10 17:43:18 +02:00
Girish Ramakrishnan
86c4db8f22 bugs in syslog parsing 2024-09-10 13:46:13 +02:00
Girish Ramakrishnan
8c0c9981de remove usage of nsyslog-parser-2
this module is somehow parsing the syslog incorrectly causing
incorrect directories being created in the logs directory
(since appName got parsed incorrectly)
2024-09-10 13:09:43 +02:00
Girish Ramakrishnan
e5dcf78ceb unbound: setup anchor on service restart 2024-09-10 09:48:10 +02:00
Girish Ramakrishnan
92bce26e22 docker: use the system dns for app containers 2024-09-10 09:42:31 +02:00
Girish Ramakrishnan
a72c038435 cloudron-support: also need to be remove any corrupt containerd 2024-09-09 18:42:08 +02:00
Girish Ramakrishnan
6742cdf373 backups: remount remote if not mounted before a backup 2024-09-09 18:15:49 +02:00
Girish Ramakrishnan
ea72cef7f9 storage: remove getProviderStatus 2024-09-09 17:36:51 +02:00
Girish Ramakrishnan
565ad83399 add to changes 2024-09-09 09:29:54 +02:00
Girish Ramakrishnan
43f795c9e4 remove use of "Cloudron" in various descriptions 2024-09-08 19:17:35 +02:00
Girish Ramakrishnan
1589cfb639 tz: add note in backup and update UI 2024-09-08 18:20:15 +02:00
Girish Ramakrishnan
a9b9931aa8 backups: do not overflow the schedule timings 2024-09-08 15:51:07 +02:00
Girish Ramakrishnan
1cd577cc65 filesystem: remove debug warning 2024-09-08 15:25:49 +02:00
Johannes Zellner
13d8db3daa For the moment new checklist items on update are acknowledged 2024-09-07 09:37:39 +02:00
Girish Ramakrishnan
40c4a01bc0 cloudron-support: ipv6 check 2024-09-06 17:20:52 +02:00
Girish Ramakrishnan
4301c70ba7 exoscale: add sos AT-VIE-2 region 2024-09-02 22:01:29 +02:00
Girish Ramakrishnan
d5e9e556ab digitalocean: add LON1 region 2024-09-02 20:58:14 +02:00
Girish Ramakrishnan
bdf9e04963 memory: ensure slider is always usable 2024-08-30 12:07:55 +02:00
Girish Ramakrishnan
b95285365d 8.1.0 changes 2024-08-28 11:51:01 +02:00
Girish Ramakrishnan
abf445e969 docker: fix rounding
toFixed() returns a string!
2024-08-28 11:45:53 +02:00
Girish Ramakrishnan
e988e3a303 storage: fix noop test 2024-08-27 15:16:18 +02:00
Girish Ramakrishnan
dca548b8a0 apptask: better progress message 2024-08-26 17:26:23 +02:00
Girish Ramakrishnan
56ecfdb4eb Fix crash on missing translation 2024-08-26 17:26:12 +02:00
Johannes Zellner
7640851aa9 dashboard: notification items need more padding on mobile 2024-08-23 19:48:04 +02:00
Johannes Zellner
d9301160e1 dashboard: give notification header more horizontal space 2024-08-23 19:45:27 +02:00
Johannes Zellner
3656d7f631 frontend: fix translation resolver to actually fallback to english 2024-08-23 19:41:58 +02:00
Johannes Zellner
9f89b07777 frontend: ensure API_ORIGIN is always set 2024-08-23 19:28:26 +02:00
Johannes Zellner
199dbff7b1 frontend: rework i18n and replace all superagent calls with pankow fetcher 2024-08-23 19:17:23 +02:00
Johannes Zellner
88b8cb48fc Deliver translation files as content type json 2024-08-23 18:34:53 +02:00
Johannes Zellner
e8b3232966 frontend: replace more superagent with pankow fetcher 2024-08-23 18:34:53 +02:00
Johannes Zellner
5de7537c71 frontend: replace superagent with pankow fetcher in DirectoryModel 2024-08-23 12:19:47 +02:00
Johannes Zellner
4706313239 frontend: update dependencies 2024-08-23 12:19:47 +02:00
Girish Ramakrishnan
d32819da4e i18n: fix crash if language file is missing 2024-08-23 10:20:35 +02:00
Girish Ramakrishnan
b6becae396 make TRANSLATIONS_DIR a constant 2024-08-23 10:09:21 +02:00
Johannes Zellner
d310c5746e dashboard: improve admin checklist display in postinstall dialog 2024-08-20 19:00:19 +02:00
Johannes Zellner
e2f4e9f30a filemanager: overwrite on upload by default for now 2024-08-20 18:31:31 +02:00
Girish Ramakrishnan
44011afd14 apps: remove port min/max tooltip
min should also be 1, otherwise you cannot go back to say port 53
2024-08-20 18:18:24 +02:00
Girish Ramakrishnan
cebaa71ce1 cloudron-support: improved dns check 2024-08-20 16:52:48 +02:00
Johannes Zellner
0ed9105a05 frontend: just use vue essential linter ruleset 2024-08-19 19:27:15 +02:00
Johannes Zellner
69ecbe5ad7 filemanager: fix upload cancellation 2024-08-19 17:09:04 +02:00
Johannes Zellner
a218761e99 frontend: fix various linter issues 2024-08-19 16:53:10 +02:00
Johannes Zellner
71d167d5fb Use local eslint in frontend 2024-08-19 16:12:43 +02:00
Johannes Zellner
aabdea8627 New sftp addon version to not overwrite files 2024-08-19 14:38:53 +02:00
Johannes Zellner
f220a1384c frontend: do not set content-length header on upload 2024-08-19 14:19:47 +02:00
Johannes Zellner
e438ade08e frontend: update pankow 2024-08-19 13:30:59 +02:00
Johannes Zellner
ed1d537f60 Use sftp addong 3.8.9 to fix file upload on drop 2024-08-19 12:31:10 +02:00
Johannes Zellner
d59bc05f12 filemanager: support multi folder/files drops 2024-08-19 12:23:35 +02:00
Johannes Zellner
4608301f1c frontend: update dependencies 2024-08-19 11:47:43 +02:00
Girish Ramakrishnan
a865320e3a 8.0.4 changes 2024-08-18 10:40:40 +02:00
Girish Ramakrishnan
bc8c01900b HOST_PORT_MIN is incorrect 2024-08-17 16:32:56 +02:00
Girish Ramakrishnan
9704eefc21 backupcleaner: do not remove the backup in progress
the backup cleaner erroneously removes any "creating" state backups.
backups that are stuck are cleaned up elsewhere already (in the
backup retention logic with discardReason of "creating-too-long").
the missing backup logic is intended for any upstream lifecycle policies.
2024-08-15 15:53:31 +02:00
Girish Ramakrishnan
52cd52d83c lint 2024-08-15 15:46:19 +02:00
Girish Ramakrishnan
4a29371907 s3: sometimes message is null and only code is valid 2024-08-13 07:08:33 +02:00
Girish Ramakrishnan
1e5e4e3189 ionos: add contract-owned eu-central-3 2024-08-12 15:56:18 +02:00
Girish Ramakrishnan
041f7da59b backups: make noop upload work again 2024-08-12 10:05:14 +02:00
Girish Ramakrishnan
4dae3447d6 backups: noop provider has no location 2024-08-12 09:58:44 +02:00
Girish Ramakrishnan
7391af6f08 tail does not support doubledash it seems 2024-08-10 11:13:07 +02:00
Girish Ramakrishnan
8a640c8219 better app autoupdate logs 2024-08-10 11:04:17 +02:00
Girish Ramakrishnan
2857582f46 add note on UI timestamps 2024-08-09 14:57:50 +02:00
Johannes Zellner
1d80f03c38 dashboard: remove mailbox import/export feature 2024-08-08 15:48:47 +02:00
Johannes Zellner
d7c20048fe dashboard: remove random console.log 2024-08-08 15:39:09 +02:00
Johannes Zellner
cbbdb77a6e dashboard: remove hidden user import/export feature 2024-08-08 15:39:09 +02:00
Girish Ramakrishnan
2ff995aa95 filemanager: do not respond again 2024-08-08 15:20:50 +02:00
Girish Ramakrishnan
21705a0e96 volumes: /mnt/volumes is reserved 2024-08-08 14:45:50 +02:00
Girish Ramakrishnan
c03da3be54 volumes: check provider instead of hostPath 2024-08-08 14:41:43 +02:00
Girish Ramakrishnan
69f48ed11a apps: do not log app logs to output 2024-08-07 15:51:04 +02:00
Johannes Zellner
caa0c342a4 sftp: restore mode and owner 2024-08-01 21:44:34 +02:00
Johannes Zellner
01b4388b3c Update dependencies 2024-08-01 18:28:29 +02:00
Girish Ramakrishnan
b870f98ec2 proxy-middleware: no more a middleware 2024-07-30 13:34:41 +02:00
Girish Ramakrishnan
a5249102f2 proxy-middleware: just pass a string 2024-07-30 12:04:35 +02:00
Girish Ramakrishnan
5aa0c57a74 proxy-middleware: remove https and custom headers 2024-07-30 11:46:54 +02:00
Girish Ramakrishnan
053b076af0 proxy-middleware: remove via header and cookie support 2024-07-30 11:35:46 +02:00
Girish Ramakrishnan
247309e11b use constant 2024-07-30 11:00:50 +02:00
Johannes Zellner
c9fe08e7b7 dashboard: also render checklist items in apps.html 2024-07-30 09:47:06 +02:00
Girish Ramakrishnan
468d4dd9b0 ami: imdsv2 support
https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/

One has to get a token now via PUT. This is because there is a bunch of
open proxies out there which blindly forwarded everything to internal network
including metadata requests. They have found that PUT requests don't cleanly
proxy and also AWS rejects token requests with X-Forwarded-For.
2024-07-27 14:48:42 +02:00
Johannes Zellner
6056ba6475 Another missing check for manifest.addons 2024-07-27 11:56:36 +02:00
Johannes Zellner
4f03a6fb58 dashboard: mailbox edit dialog is not really a form with submit action
As a form with a submit button the browser tries to be smart which will
trigger the next button tag as enter action on a textinput
2024-07-26 18:57:45 +02:00
Girish Ramakrishnan
d8aa4bc5e4 filemanager: fix sending of double header
we should not proceed to notFoundHandler if proxy handled it just fine
2024-07-26 11:58:41 +02:00
Girish Ramakrishnan
06e46e0f1e 8.0.3 changes 2024-07-26 09:09:35 +02:00
Girish Ramakrishnan
731295f708 system: simplify logic 2024-07-25 17:50:50 +02:00
Girish Ramakrishnan
9399040cd3 Fix log recursion
shell.sudo logs output to stdout/stderr intentionally. It is not meant
for scripts that generate much output (basically scripts/* files).

core of the issue is that none of the log commands require to use sudo.
they can just use normal tail. only app logs requires sudo because of the
logPaths directive in the manifest.
2024-07-25 17:48:58 +02:00
Johannes Zellner
9f9fde5811 frontend: fix clear view in logs viewer 2024-07-25 17:44:20 +02:00
Johannes Zellner
cbc46a8229 dashboard: support links/markdown in checklist items 2024-07-25 17:40:15 +02:00
Girish Ramakrishnan
fb11997430 Add note on automatic upgrades 2024-07-25 17:09:46 +02:00
Girish Ramakrishnan
b6fbc46b58 Revert "Add option to not log shell subprocess stdout+stderr"
This reverts commit 51bb2d2bc2.
2024-07-25 11:53:56 +02:00
Johannes Zellner
21de2513e7 frontend: fix all usage of file upload without multipart 2024-07-25 11:18:14 +02:00
Johannes Zellner
51bb2d2bc2 Add option to not log shell subprocess stdout+stderr
When tailing the box log file this leads to logline recursion
2024-07-25 10:22:02 +02:00
Girish Ramakrishnan
8d9043e590 logviewer: reduce it back to 100
a lot of delay with 300
2024-07-23 17:27:36 +02:00
Johannes Zellner
59c3e8817c frontend: Reduce initial logs to 300 lines only 2024-07-23 16:33:56 +02:00
Girish Ramakrishnan
3132b3035a 8.0.2 changes 2024-07-23 08:34:26 +02:00
Girish Ramakrishnan
7ebf5ca16a Bring back upload route to keep e2e happy
let's maybe remove it in next release
2024-07-23 08:28:44 +02:00
Johannes Zellner
d96f132dc0 frontend: reduce DOM node creation on very fast logstreams and cap to 1k loglines 2024-07-22 23:55:47 +02:00
Girish Ramakrishnan
b26ff08a3c shell: copy over code and signal values from cp object 2024-07-22 21:24:27 +02:00
Girish Ramakrishnan
44678cf5f1 sshfs: if remote copy fails, fallback to sshfs based copy
remote copy can file if there is no cp in the remote . for example,
if it was a windows server.
2024-07-22 20:53:19 +02:00
Girish Ramakrishnan
5084ee761e update postgresql conf notes 2024-07-22 18:53:51 +02:00
Girish Ramakrishnan
91f50ae949 mysql: add template custom.cnf 2024-07-22 18:53:51 +02:00
Johannes Zellner
15f04edcf1 frontend: update dependencies 2024-07-22 18:00:33 +02:00
Johannes Zellner
01945675ed Check if addons exists in database import 2024-07-22 16:45:13 +02:00
Johannes Zellner
185c16c3e2 remove apps upload api in favor of sftp container api 2024-07-22 16:20:15 +02:00
Johannes Zellner
d25814b84b Remove stray console.log 2024-07-22 15:07:43 +02:00
Girish Ramakrishnan
a09a3fd012 postgresql: add template custom.conf 2024-07-22 14:44:23 +02:00
Johannes Zellner
871fd83148 Use new sftp service image without multipart file upload 2024-07-22 13:29:56 +02:00
Girish Ramakrishnan
dd8bc493e7 postgresql: add custom.conf include 2024-07-22 12:50:23 +02:00
Johannes Zellner
44d3baf51a dashboard: show longer pretty datetime for backups 2024-07-21 20:45:34 +02:00
Girish Ramakrishnan
c85c0558b9 multipart: cleanup files after reading their contents
one idea is just use express.raw() . however, we have to implement some
file size limit there.

one case this does not handle is aborted uploads from a box.service restart.
for this rare case, a server reboot will clean up /tmp anyway.
2024-07-19 23:11:26 +02:00
Girish Ramakrishnan
7f11699fac remove urlencoded
we don't use this in our API
2024-07-19 22:44:22 +02:00
Girish Ramakrishnan
525e48ae59 json middleware is part of Express v4.16.0 2024-07-19 22:26:24 +02:00
Johannes Zellner
a6369a7dde Fix linter error 2024-07-19 22:24:34 +02:00
Girish Ramakrishnan
d5ea99603f backups: give is a low oomScoreAdjust to not get killed 2024-07-19 13:05:09 +02:00
Girish Ramakrishnan
083432cbfe test: add EnsureFileSizeStream test 2024-07-18 15:39:45 +02:00
Girish Ramakrishnan
dbbce4160d tgz: underflow/overflow proxy stream
In tar, the entry header contains the file size. If we don't provide it those many bytes, the tar will become corrupt
Linux provides no guarantee of how many bytes can be read from a file. This is the case with sqlite and log files
which are accessed by other processes when tar is in action. This class handles overflow and underflow
2024-07-18 15:13:38 +02:00
Girish Ramakrishnan
885aac69c5 tgz: handle addEntryToPack to error 2024-07-18 14:47:31 +02:00
Girish Ramakrishnan
b3c301fc2a lint 2024-07-18 13:31:29 +02:00
Girish Ramakrishnan
01deb4d285 update: updateConfig can be missing values, selectively update db 2024-07-17 08:58:43 +02:00
Girish Ramakrishnan
aeddaa4566 apps: rework portBindings
ports is REST API input . Map of env var to the host port
portBinding is the database structure. Map of env var to host port, count, type etc

also, rename portCount -> count in various places to keep things consistent
2024-07-17 00:25:47 +02:00
Girish Ramakrishnan
eb314ef507 lint 2024-07-16 22:07:22 +02:00
Girish Ramakrishnan
620c49cf76 Fix signature of checkForPortBindingsConflict 2024-07-16 19:31:54 +02:00
Girish Ramakrishnan
6d73dfdb40 parse port count as integer 2024-07-16 19:28:22 +02:00
Girish Ramakrishnan
232cdb8cb1 cloudron-support: do cert check before site check 2024-07-16 19:21:09 +02:00
Girish Ramakrishnan
fd53174099 lint 2024-07-16 10:32:37 +02:00
Girish Ramakrishnan
9bf240d83b update: handle change in secondary domains and multiDomain flag 2024-07-16 10:32:31 +02:00
Girish Ramakrishnan
421567ff14 Add to changes 2024-07-15 21:52:04 +02:00
Girish Ramakrishnan
ce05008fce setup: when activated redirect to adminFqdn 2024-07-15 21:52:01 +02:00
Girish Ramakrishnan
a250cb9fe2 capitalize 2024-07-15 21:08:16 +02:00
Girish Ramakrishnan
012f8bc14e setup: show message on how to redo setup 2024-07-15 21:08:13 +02:00
Girish Ramakrishnan
11dce549bd refactor init sequence 2024-07-15 18:52:22 +02:00
Girish Ramakrishnan
5b567ac941 lint 2024-07-15 16:57:47 +02:00
Girish Ramakrishnan
5b103c78e5 lint 2024-07-15 16:54:48 +02:00
Girish Ramakrishnan
bc96f9c5e5 update: match the ui in settings page 2024-07-15 16:28:00 +02:00
Girish Ramakrishnan
d97d82b225 settings: do not show "skip backup" when updates is blocked
https://forum.cloudron.io/topic/12092/imho-the-skip-backup-checkbox-makes-no-sense
2024-07-15 09:48:04 +02:00
Girish Ramakrishnan
e9b6002f63 s3: fix exists check 2024-07-14 22:04:12 +02:00
Girish Ramakrishnan
704999a05f backups: fix incorrect "memoryLimit must be a number" error 2024-07-14 18:21:12 +02:00
Girish Ramakrishnan
ba99e3b9b7 already in setup script now 2024-07-14 17:06:13 +02:00
Girish Ramakrishnan
9adeaed1b9 support: add hidden troubleshooting section 2024-07-12 16:20:25 +02:00
Girish Ramakrishnan
10bd2e930f support: remove commented out sections 2024-07-12 14:25:11 +02:00
Girish Ramakrishnan
07396c9824 Revert "support: add route to repair apps"
This reverts commit 0bab0ed748.

It's better to somehow integrate this into the dashboard ...
2024-07-12 14:22:47 +02:00
Girish Ramakrishnan
bf34b13b7f cloudron-support: add --patch 2024-07-12 11:06:06 +02:00
Girish Ramakrishnan
0bab0ed748 support: add route to repair apps 2024-07-11 18:30:29 +02:00
Girish Ramakrishnan
8754a208b1 tgz: preserve mode 2024-07-11 18:10:40 +02:00
Johannes Zellner
19100c7999 dashboard: make app update section a bit more explicit 2024-07-11 17:51:20 +02:00
Johannes Zellner
d98ec77abf Update German translation 2024-07-11 16:47:39 +02:00
Johannes Zellner
34c2decd91 Remove indonesian and portuguese translation as they are way below 50% 2024-07-11 15:48:43 +02:00
Johannes Zellner
09fb4ea89f Add Indonesian (lang.id) translation name 2024-07-11 15:44:38 +02:00
Girish Ramakrishnan
d6bb32aead syncer: expose as async 2024-07-10 19:10:55 +02:00
Girish Ramakrishnan
3a21191fba tgz: fix error handling 2024-07-10 19:10:24 +02:00
Girish Ramakrishnan
ad4e0ba9aa tests: fix storage test 2024-07-08 22:29:45 +02:00
Girish Ramakrishnan
baf598099f rsync: fix upload logic to match new upload api 2024-07-08 15:21:56 +02:00
Johannes Zellner
7d017d83d6 dashboard: do not open email client setup if disabled 2024-07-08 15:19:00 +02:00
Girish Ramakrishnan
7911780a16 const 2024-07-08 13:18:22 +02:00
Girish Ramakrishnan
1dc6b40a68 tgz: extract using tar-stream directly
we used have a fork of tar-fs. using tar-stream directly gives us
more control
2024-07-08 13:06:56 +02:00
Girish Ramakrishnan
dd9e6e63ad apptask: only delete image if it is different 2024-07-08 12:59:34 +02:00
Girish Ramakrishnan
30633e7820 lint 2024-07-08 10:47:07 +02:00
Girish Ramakrishnan
acfc67ed0a backuptask: typo in usage of getAvailableSize 2024-07-08 10:46:28 +02:00
Girish Ramakrishnan
a99a8ef382 services: fix crash because of missing safe() 2024-07-08 10:30:10 +02:00
Girish Ramakrishnan
7aec713e6c shell: fix streaming of stdout/stderr with sudo 2024-07-08 10:09:00 +02:00
Girish Ramakrishnan
60c4dd3875 sudo: add explicit captureStdout flag 2024-07-08 09:58:25 +02:00
Girish Ramakrishnan
7d8ba8d42c tests: datalayout 2024-07-07 20:23:32 +02:00
Girish Ramakrishnan
7ff7842441 lint 2024-07-05 21:56:33 +02:00
Girish Ramakrishnan
bcf497b460 translation.js -> translations.js
kept confusing my why i can't find this file! this is in line
with the rest of our code
2024-07-05 12:45:27 +02:00
Girish Ramakrishnan
bf51a60986 change args of translation.translate 2024-07-05 12:42:33 +02:00
Girish Ramakrishnan
41809d1ca8 mailer: format is not used 2024-07-05 12:20:30 +02:00
Girish Ramakrishnan
acb1445270 make these const 2024-07-05 11:41:07 +02:00
Girish Ramakrishnan
86530df37e mailer: add html version of test mail 2024-07-05 11:07:51 +02:00
Girish Ramakrishnan
b64b513b14 Revert "use node-tar for extract"
This reverts commit 285feb4f8b.
2024-07-05 09:26:38 +02:00
Girish Ramakrishnan
285feb4f8b use node-tar for extract
we will switch over our tgz module to node-tar. Main advantage is that
it is used by npm. Currently, we have our own fork to ignore stat errors
in the other module.

unfortunately, I cannot get this to work with the create logic. It doesn't
support path modification - https://github.com/isaacs/node-tar/issues/271
so, will revert this immediately and keep this for future
2024-07-05 09:26:28 +02:00
Girish Ramakrishnan
c6f4395578 Fix deprecation of Buffer.slice 2024-07-05 09:26:28 +02:00
Johannes Zellner
4981854c7f dashboard: do not duplicate app info in update section 2024-07-04 16:57:54 +02:00
Girish Ramakrishnan
65f6ff35e0 Update translations 2024-07-04 09:28:18 +02:00
Johannes Zellner
d892cc5763 Add comment how to debug the openid provider 2024-07-03 11:33:58 +02:00
Johannes Zellner
d122ece8e9 Attempt server side copy on sshfs via ssh exec
only so far tested agains hetzner storage boxes which apparently run BSD
unix tools
2024-07-02 19:51:34 +02:00
Girish Ramakrishnan
a363e508b6 ami: disable route53
we got an email from AWS team that their policy prevents collection
of AMI credentials in AMI images
2024-07-02 16:09:36 +02:00
Girish Ramakrishnan
e481606d0e lint 2024-07-02 16:09:36 +02:00
Girish Ramakrishnan
a1e2c9fd08 cloudron-support: print_system 2024-07-01 14:08:55 +02:00
Girish Ramakrishnan
f5931abdeb cloudron-support: print ubuntu version 2024-07-01 13:38:18 +02:00
Girish Ramakrishnan
4c9e05b08f cloudron-support: add netplan and product info 2024-07-01 08:24:01 +02:00
Girish Ramakrishnan
9c34727e88 cloudron-support: dig does not return error on SERVFAIL 2024-07-01 07:57:21 +02:00
Girish Ramakrishnan
939cd94ebb typo 2024-07-01 07:55:08 +02:00
Johannes Zellner
4a33415b06 Set notes on existing apps to empty string if NULL 2024-06-29 09:52:41 +02:00
Girish Ramakrishnan
082e659c7b disable rpcbind
rpcbind is required for NFSv2 and v3 . It seems this gets installed
by nfs-common. It was never used by us since the firewall blocks
port 111 anyways.

NFSv3 needs 2049 for NFS, 111 for portmap, 635 for mountd, 4045 for NLM, 4046 for NSM, 4049 for rquota ...

NFSv4 works better because there's just a single target port, plus the "heartbeat" of lease renewal would keep the TCP/IP session alive.

https://serverfault.com/questions/949127/nfs-client-firewall-settings-and-rpcbind
https://docs.redhat.com/en/documentation/Red_Hat_Enterprise_Linux/6/html/Storage_Administration_Guide/s2-nfs-methodology-portmap.html#s2-nfs-methodology-portmap
https://community.netapp.com/t5/Tech-ONTAP-Blogs/NFSv3-and-NFSv4-What-s-the-difference/ba-p/441316
2024-06-27 20:37:08 +02:00
Girish Ramakrishnan
a8059c49e9 lint 2024-06-27 16:50:31 +02:00
Johannes Zellner
f7b14b2ee8 dashboard: only show postinstall if notes are not just empty 2024-06-27 16:20:19 +02:00
Johannes Zellner
581a294af1 dashboard: give the checklist done button some space 2024-06-27 13:58:58 +02:00
Johannes Zellner
40e8ba38f0 dashboard: fix app grid item tooltip 2024-06-27 13:49:20 +02:00
Girish Ramakrishnan
65f4ec0f43 cloudron-support: check dns now and not just unbound 2024-06-27 12:58:37 +02:00
Johannes Zellner
8748ba1226 dashboard: show number of pending checklist items 2024-06-25 20:38:24 +02:00
Johannes Zellner
2ad8ee18a0 dashboard: keep checklist items up to date 2024-06-25 18:01:31 +02:00
Johannes Zellner
8b9dc5a6bf dashboard: fix eventlog for mailbox changes 2024-06-25 17:54:46 +02:00
Johannes Zellner
a1a6570ee3 dashboard: show mailbox displayname in eventlog 2024-06-25 17:27:37 +02:00
Girish Ramakrishnan
6c68f7da2e apps: updateTime should be null if never updated
"TIMESTAMP NULL" is an attribute modifier to make the column nullable.
Without it, if you assign null, the timestamp becomes the current time!
2024-06-25 17:24:02 +02:00
Girish Ramakrishnan
ccd5f6c2e5 app: move the installation time down 2024-06-25 17:24:02 +02:00
Johannes Zellner
73b20ae809 dashboard: do not show sso info in postinstall dialog 2024-06-25 16:56:33 +02:00
Johannes Zellner
a4dd6cc928 dashboard: remove checkbox in background image branding 2024-06-25 16:26:06 +02:00
Girish Ramakrishnan
6f37bde55d import: add prefix support
it is incorrect to ignore the prefix. the keys (for s3) and permissions (managed mounts)
might work only inside the prefix.
2024-06-25 13:41:21 +02:00
Girish Ramakrishnan
8f1f3cea18 doc: add import fields 2024-06-25 13:41:21 +02:00
Johannes Zellner
f715e21306 oidc: raise login event on consent not login form itself 2024-06-25 13:24:46 +02:00
Girish Ramakrishnan
d9b478cf1f rename setupStorage to setupManagedStorage 2024-06-25 13:06:40 +02:00
Girish Ramakrishnan
36a768eb60 backups: document structure of backupConfig
I keep forgetting this, let's write this up once and for all
2024-06-25 13:06:40 +02:00
Johannes Zellner
0ebe6e545d dashboard: fix mobile dark-mode for back action 2024-06-25 12:26:18 +02:00
Johannes Zellner
5fb295e044 frontend: Update dependencies 2024-06-25 12:18:54 +02:00
Johannes Zellner
be7e11a4f6 frontend: use new busy state on the directoryview 2024-06-25 11:59:14 +02:00
Girish Ramakrishnan
d13bf9ac74 eventlog: fix display of directoryserver login event 2024-06-24 21:42:03 +02:00
Girish Ramakrishnan
e909b6e643 mail: mail manager role cannot change server location 2024-06-24 21:31:29 +02:00
Girish Ramakrishnan
9555a93ddc redis: don't send password when noPassword 2024-06-24 21:25:48 +02:00
Johannes Zellner
1d9ad35019 dashboard: show postinstall message for admin notes unless set 2024-06-24 19:59:02 +02:00
Johannes Zellner
78aee78d9c dashboard: better login page background image label 2024-06-24 19:34:32 +02:00
Johannes Zellner
4b96d5879c dashboard: show who and when a checklist item was acked 2024-06-24 19:11:38 +02:00
Johannes Zellner
20396a8c7d Adjust checklist item api to support audits trail 2024-06-24 19:09:03 +02:00
Johannes Zellner
8510b12841 dashboard: show/hide done checklist items 2024-06-24 16:53:57 +02:00
Girish Ramakrishnan
345f9541fe mongodb: do not apply memory limit when no avx 2024-06-23 21:06:30 +02:00
Johannes Zellner
c1c864ced7 dashboard: show app install time in info section 2024-06-22 15:50:50 +02:00
Girish Ramakrishnan
7a440a32d1 ldap connector: make auto-create true by default 2024-06-22 10:35:04 +02:00
Johannes Zellner
ef1431f89b dashboard: sort by location in app list by default 2024-06-21 21:18:22 +02:00
Johannes Zellner
57cf0ec074 dashboard: improve app list view layout 2024-06-21 21:17:05 +02:00
Girish Ramakrishnan
d795507ddd Update translations 2024-06-21 18:07:00 +02:00
Girish Ramakrishnan
c3aafb2979 even more changes 2024-06-21 17:09:17 +02:00
Johannes Zellner
93d4472932 dashboard: improve list view column headers 2024-06-21 16:54:32 +02:00
Johannes Zellner
69934be88c frontend: remove home icon in filemanager 2024-06-21 16:45:56 +02:00
Johannes Zellner
8638bfb30b dashboard: show full mailbox address in eventlog 2024-06-21 15:48:06 +02:00
Johannes Zellner
5b3d6a3957 dashboard: do not show number of active app filters 2024-06-21 15:39:04 +02:00
Johannes Zellner
94dd0644d0 frontend: Mention /app/data in filemanager breadcrumbs 2024-06-21 15:39:04 +02:00
Girish Ramakrishnan
f089329e12 more changes 2024-06-21 15:21:59 +02:00
Johannes Zellner
8554d374c9 dashboard: eventlog fix cpu quota display 2024-06-21 14:49:11 +02:00
Johannes Zellner
424ec1c90d dashboard: show pretty memory limits in eventlog 2024-06-21 14:43:10 +02:00
Johannes Zellner
ce2f1b4170 dashboard: fix colspan typo 2024-06-21 14:42:58 +02:00
Johannes Zellner
ce1146a9ef frontend: set dark background as early as possible to avoid white flashing 2024-06-21 10:57:21 +02:00
Johannes Zellner
f065821587 frontend: slightly improve local development 2024-06-21 10:57:01 +02:00
Johannes Zellner
18c518f385 dashboard: improve postinstall dialog header 2024-06-20 15:57:45 +02:00
Johannes Zellner
6ba1953acb Revert "lint"
This reverts commit 36887abf88.
2024-06-20 15:47:49 +02:00
Johannes Zellner
324ee4641f dashboard: ensure configure button is not overlapping the checklist indicator 2024-06-20 14:58:45 +02:00
Johannes Zellner
9ee4490498 frontend: also update the package lock file 2024-06-20 13:36:36 +02:00
Johannes Zellner
0fa32c9572 frontend: update pankow for dark mode fixes 2024-06-20 13:36:13 +02:00
Johannes Zellner
b3e5563e15 dashboard: checklist bubble goes right 2024-06-20 13:15:15 +02:00
Johannes Zellner
55038dee51 frontend: update dependencies 2024-06-20 13:06:41 +02:00
Girish Ramakrishnan
b54eaf2964 more changes 2024-06-20 13:02:54 +02:00
Johannes Zellner
98e97a0f9b dashboard: show pending admin checklist in apps list/grid 2024-06-18 16:37:21 +02:00
Johannes Zellner
f15b4a4f4b dashboard: Better state handling for app info notes 2024-06-18 15:49:52 +02:00
Johannes Zellner
bd7641f502 frontend: fix autoscroll in logviewer 2024-06-17 18:25:50 +02:00
Girish Ramakrishnan
2d04ec2308 appstore: check response is an image 2024-06-15 17:31:49 +02:00
Girish Ramakrishnan
ba0ab68f50 appstore: validate the id and the version 2024-06-15 17:11:11 +02:00
Girish Ramakrishnan
825fe21bd9 lint 2024-06-15 17:03:54 +02:00
Girish Ramakrishnan
072ca73259 Update manifestformat for more permissive ids 2024-06-15 12:38:53 +02:00
Girish Ramakrishnan
b333a136e8 cloudron-support: some newlines 2024-06-14 17:08:23 +02:00
Girish Ramakrishnan
e34cf7fd77 cloudron-support: more fixes to --recreate-docker 2024-06-14 13:04:40 +02:00
Girish Ramakrishnan
1c7099b3f0 typo 2024-06-14 11:45:15 +02:00
Girish Ramakrishnan
d74ee441ac oidc: add doc link to various endpoints 2024-06-14 11:37:42 +02:00
Girish Ramakrishnan
7bad90009e cloudron-support: better recreate-docker 2024-06-14 11:02:53 +02:00
Girish Ramakrishnan
424bc588f6 cloudron-support: implement --recreate-docker 2024-06-13 18:51:11 +02:00
Girish Ramakrishnan
852e1e1687 cloudron-support: implement --recreate-containers 2024-06-13 17:55:22 +02:00
Girish Ramakrishnan
649c06b641 notification: do not send login notification for external users 2024-06-13 16:55:35 +02:00
Girish Ramakrishnan
6b4df0bd65 lint 2024-06-13 16:55:35 +02:00
Johannes Zellner
e67324b05c Update translations 2024-06-13 16:02:13 +02:00
Johannes Zellner
d688f5e080 dashboard: slightly better admin notes edit handling 2024-06-13 15:48:35 +02:00
Johannes Zellner
c3f9d688f1 frontend: more dark mode fixes 2024-06-13 12:19:03 +02:00
Johannes Zellner
7affc6e987 frontend: initial dark mode for filemananger 2024-06-12 19:57:21 +02:00
Johannes Zellner
9f26608681 frontend: remove unused css 2024-06-12 19:37:10 +02:00
Girish Ramakrishnan
d34b102e52 mandatory2fa: fix workflow when using external LDAP
* Always allow the mandatory 2fa setting to be saved
* Show warning for user if they have no 2fa setup and if not external 2fa
* If they get locked out anyway, they have to use CLI tool
* redirect for mandatory 2fa only if not external 2fa as well
2024-06-12 12:26:40 +02:00
Girish Ramakrishnan
077f95049e test: user directory profile route 2024-06-12 11:11:56 +02:00
Girish Ramakrishnan
b570f2f77d userdirectory: add eventlog entry 2024-06-12 10:52:10 +02:00
Girish Ramakrishnan
b4e7e394c3 split routes and model code into user-directory.js 2024-06-12 10:49:01 +02:00
Girish Ramakrishnan
e1f87161a8 mandatory 2fa: revoke oidc sessions of non-2fa users 2024-06-12 10:16:49 +02:00
Johannes Zellner
57bf3709f3 proxyauth: also preserve request uri for proxyauth addon apps 2024-06-11 19:15:58 +02:00
Johannes Zellner
9d258d33cf Use 127.0.0.53 as a resolver for nginx 2024-06-11 18:59:19 +02:00
Johannes Zellner
62e322c451 proxyauth: stash path and query for further use in the session 2024-06-11 18:59:19 +02:00
Johannes Zellner
9a04ee2d1f frontend: update pankow for inputdialog fixes 2024-06-11 18:59:19 +02:00
Girish Ramakrishnan
5852fac71a backups: validate mountOptions is an object for managed providers 2024-06-11 14:40:54 +02:00
Johannes Zellner
f315a378dc frontend: also selectively show filemanager in terminal if localstorage addon exists 2024-06-11 14:01:57 +02:00
Johannes Zellner
dcee792aaa frontend: show filemanager,terminal and restart buttons only where it makes sense 2024-06-11 14:01:57 +02:00
Girish Ramakrishnan
d0df897f93 typo 2024-06-11 14:01:13 +02:00
Johannes Zellner
915e3ecc94 dashboard: Show eventlog source IP in details 2024-06-11 12:05:58 +02:00
Johannes Zellner
76dadd1f8b dashboard: do not show eventlog source ip - too noisy with ipv6 2024-06-11 11:40:04 +02:00
Johannes Zellner
73fdcae916 dashboard: Show eventlog source in app view 2024-06-11 11:36:49 +02:00
Girish Ramakrishnan
941162a05f networking: ipv4 configuration can be missing 2024-06-10 19:18:11 +02:00
Johannes Zellner
22b8ec6144 frontend: fixes to use pankow-viewers 2024-06-10 11:59:34 +02:00
Girish Ramakrishnan
a0c7f3f896 pin superagent to 9.0.1
9.0.2 broke basic ipv6 queries -https://github.com/ladjs/superagent/pull/1805
2024-06-10 11:28:33 +02:00
Girish Ramakrishnan
692be297b3 app proxy: protect code accessing containerId 2024-06-10 11:23:29 +02:00
Girish Ramakrishnan
db3eabcd2f mail: haraka limits plugin fix
https://github.com/haraka/haraka-plugin-limit/pull/63
2024-06-10 09:43:14 +02:00
Johannes Zellner
fee78bb488 frontend: ask user if terminal should be really closed on ctrl+w 2024-06-09 15:35:10 +02:00
Johannes Zellner
dda6f43b8a frontend: update dependencies 2024-06-09 15:27:21 +02:00
Girish Ramakrishnan
b5fad74ea0 Update packages 2024-06-08 22:37:20 +02:00
Girish Ramakrishnan
ef42106a16 redis: cleanup tmp rdb files 2024-06-08 22:34:30 +02:00
Girish Ramakrishnan
bba1922120 dockerproxy: fix test 2024-06-08 22:26:34 +02:00
Girish Ramakrishnan
f386c326e2 apptask: only move app uses localstorage addon 2024-06-06 16:26:02 +02:00
Girish Ramakrishnan
3b26f6f5ea use optional chaining 2024-06-06 15:19:19 +02:00
Girish Ramakrishnan
52701e1173 add note 2024-06-06 15:16:04 +02:00
Girish Ramakrishnan
3c7d24916c backups: show generic error in the dialog 2024-06-06 11:41:33 +02:00
Girish Ramakrishnan
4fac0cb535 const fixes 2024-06-06 11:33:42 +02:00
Girish Ramakrishnan
00f6ef7603 backups: cannot change config in demo mode 2024-06-06 11:32:15 +02:00
Girish Ramakrishnan
556b9fe20c test: fix updatechecker test 2024-06-03 19:34:22 +02:00
Girish Ramakrishnan
3dcd0975f7 test: fix various routes tests
* system/disks routes is gone
* provision routes now return 405 instead of 409 when re-setup/re-activated
2024-06-03 19:27:23 +02:00
Girish Ramakrishnan
db7e88e302 Update translations 2024-06-03 15:35:39 +02:00
Girish Ramakrishnan
9c5fb2823c Update test packages 2024-06-03 10:38:53 +02:00
Girish Ramakrishnan
d12b2ae2db Revert "database: change db fields"
This reverts commit 0227ae1d96.

unclear why this doesn't work now
2024-06-03 10:37:59 +02:00
Girish Ramakrishnan
449d68122b progressstream: add stats func 2024-05-31 16:55:41 +02:00
Girish Ramakrishnan
0227ae1d96 database: change db fields 2024-05-31 16:55:41 +02:00
Girish Ramakrishnan
265e58e5cb ovh: add rbx region 2024-05-29 16:53:04 +02:00
Girish Ramakrishnan
9054f30aef lint 2024-05-25 13:42:44 +02:00
Girish Ramakrishnan
36887abf88 lint 2024-05-25 13:10:53 +02:00
Girish Ramakrishnan
4ca5fcf472 postgresql: set process limits 2024-05-23 21:50:47 +02:00
Girish Ramakrishnan
c4b01dea22 mail: rename fields in spam acl 2024-05-23 17:04:01 +02:00
Girish Ramakrishnan
6d4cc4a6b8 const fixes 2024-05-23 10:58:59 +02:00
Girish Ramakrishnan
4229e9921c blacklisted -> blocked 2024-05-23 09:53:47 +02:00
Johannes Zellner
92b6a7e335 dashboard: do not crash if sysinfo cache still contains removed volume info 2024-05-22 11:39:19 +02:00
Girish Ramakrishnan
cb8731b915 syslog: also replace CR (\r) 2024-05-21 16:48:29 +02:00
Johannes Zellner
0c80b7af1d dashboard: show checklist items in postinstall dialog 2024-05-20 18:13:17 +02:00
Girish Ramakrishnan
4ce9c46215 dyndns: update mail server location 2024-05-17 13:23:47 +02:00
Girish Ramakrishnan
bbf402368f lint: const 2024-05-17 13:18:53 +02:00
Girish Ramakrishnan
37d1dc7c6d add to changes 2024-05-16 14:56:57 +02:00
Johannes Zellner
a677dc3981 Fixup crontab tests 2024-05-15 15:17:42 +02:00
Johannes Zellner
77163cc1b2 remove legacy system/disks route 2024-05-15 14:34:30 +02:00
Girish Ramakrishnan
5d41a84fec add comment 2024-05-15 14:14:05 +02:00
Johannes Zellner
890de53b0a syslog: handle potential multiline syslog input 2024-05-15 13:45:32 +02:00
Johannes Zellner
a1f2b5b696 frontend: update dependencies 2024-05-13 17:49:19 +02:00
Girish Ramakrishnan
6eda037544 lint: const fixes 2024-05-13 17:02:20 +02:00
Girish Ramakrishnan
eb5b8b42dc updater: delete any old dirs from failed updates 2024-05-13 17:00:58 +02:00
Girish Ramakrishnan
4a5022d14d lint: const fixes 2024-05-13 08:43:33 +02:00
Girish Ramakrishnan
54c6f9c4f8 logs: do not push empty lines 2024-05-13 08:37:49 +02:00
Johannes Zellner
dee60e9958 dashboard: improve checklist handling 2024-05-11 11:26:46 +02:00
Johannes Zellner
bbefa38355 dashboard: show who installed an app in the eventlog 2024-05-10 17:56:05 +02:00
Girish Ramakrishnan
6681f2e5c8 netcup: dns fixes 2024-05-04 18:37:40 +02:00
Johannes Zellner
1728756dc4 dashboard: give appstore tiles more horizontal space 2024-05-03 12:30:26 +02:00
Johannes Zellner
1f0860e45d oidc: hide login form while initializing the view 2024-05-03 11:48:25 +02:00
Johannes Zellner
9eb91a3ae9 Update pankow 2024-05-02 18:18:34 +02:00
Johannes Zellner
ad50ea5aee frontend: remove primeicons 2024-05-02 15:18:48 +02:00
Johannes Zellner
73045fd7fc frontend: update dependencies 2024-05-02 15:07:07 +02:00
Johannes Zellner
11aeccc822 frontend: remove primevue from terminal 2024-05-02 15:05:04 +02:00
Johannes Zellner
310a8c1c63 frontend: remove primevue from logsviewer 2024-05-02 13:08:56 +02:00
Johannes Zellner
23153e5b86 frontend: filemanager is now without primevue 2024-05-01 14:51:16 +02:00
Johannes Zellner
130d8a1ba0 Frontend: stop using primevue confirm service 2024-05-01 14:17:44 +02:00
Johannes Zellner
8d9ecf3352 frontend: remove unused InputText 2024-05-01 13:12:54 +02:00
Johannes Zellner
6080cfa351 frontend: replace Dialogs with pankow Dialog 2024-05-01 13:11:52 +02:00
Johannes Zellner
4e04b2075f frontend: use pankow InputDialog from prompts 2024-05-01 12:53:45 +02:00
Johannes Zellner
9f415826fd frontend: remove unused margins 2024-05-01 12:53:45 +02:00
Girish Ramakrishnan
54d92b8bf7 backups: uploadPartSize only makes sense for s3 2024-05-01 12:39:32 +02:00
Girish Ramakrishnan
f1e8b91f61 backups: remove limit object from storage config
this is causing UI to get confused
2024-05-01 12:06:04 +02:00
Girish Ramakrishnan
a1bd1a0fa1 domains: add list/get/del test as normal user 2024-04-30 10:36:12 +02:00
Girish Ramakrishnan
b142cd5039 domains: when listing, send all fields
also remove the certificate key from responses
2024-04-30 09:47:50 +02:00
Girish Ramakrishnan
b548856c29 domains: remove wildcard field check
it is part of tlsConfig object
2024-04-30 09:06:04 +02:00
Girish Ramakrishnan
a0df52000a typo 2024-04-29 15:51:16 +02:00
Girish Ramakrishnan
e98a1a9767 docker container can use system dns
only mail container needs unbound for dnsbl
2024-04-29 15:48:30 +02:00
Johannes Zellner
ad2eaff60e frontend: use pankow Menu in filemanger 2024-04-29 15:39:56 +02:00
Johannes Zellner
3df7b74f65 dashboard: preserve path when relogin is required 2024-04-29 15:22:01 +02:00
Girish Ramakrishnan
67c1b2cb71 installer: remove custom nginx upgrade logic 2024-04-29 14:23:19 +02:00
Girish Ramakrishnan
6c0e84a31d installer: remove verbose extract 2024-04-29 14:14:36 +02:00
Girish Ramakrishnan
c49a440211 init-ubuntu: resolvconf is not needed anymore
unbound is still needed since it's running but not for resolv.conf
2024-04-29 13:22:19 +02:00
Girish Ramakrishnan
caedf6a8e7 remove resolvconf and enable systemd-resolved 2024-04-29 13:19:52 +02:00
Girish Ramakrishnan
203330d1b8 lint: const 2024-04-29 13:05:07 +02:00
Girish Ramakrishnan
c8d66384c7 domains: check if wildcard is boolean in tlsConfig 2024-04-29 12:52:12 +02:00
Girish Ramakrishnan
74447d2690 lint 2024-04-29 12:49:20 +02:00
Girish Ramakrishnan
b66ddedc86 domains: remove unused wildcard check 2024-04-29 12:45:57 +02:00
Girish Ramakrishnan
8df97de8c6 Ubuntu 24.04
* update docker to 26.0.1
* cloudron-syslog needs to have correct perms for fifo socket
2024-04-29 11:07:10 +02:00
Girish Ramakrishnan
cd5cae33ce dns: switch over to systemd for the host
this changes unbound to listen to 127.0.0.150 (150 is roman CL)

we cannot only bind on docker bridge because unbound is relied
upon for the initial domain setup. docker itself is only initialized
when the platform initializes
2024-04-29 11:06:03 +02:00
Girish Ramakrishnan
608ce53e7d scripts: remove unused cloudron-logs 2024-04-29 10:21:33 +02:00
Johannes Zellner
d2ae6c2353 dashboard: grid view is the default 2024-04-29 09:32:00 +02:00
Johannes Zellner
7eda1136ea oidc: starting with new .json model files is not worth a log line 2024-04-29 09:19:37 +02:00
Girish Ramakrishnan
a756fa9e9b remove dead code 2024-04-28 10:52:30 +02:00
Girish Ramakrishnan
afb5e5ac5d add to changes 2024-04-27 19:27:11 +02:00
Girish Ramakrishnan
efa1acddd4 dns: unregister domains if type is disabled 2024-04-27 18:43:31 +02:00
Girish Ramakrishnan
e00db115ad restore: fix crashes 2024-04-27 12:46:37 +02:00
Girish Ramakrishnan
366f247910 oidc: only start in set callback 2024-04-27 11:51:10 +02:00
Girish Ramakrishnan
2a6368af60 remove usage of constants.DASHBOARD_SUBDOMAIN 2024-04-27 11:10:24 +02:00
Girish Ramakrishnan
5420630453 oidc: start the server when dashboard domain is set
the activation logic has changed to use oidc flow. this requires
the oidc server to be started and available. otherwise, the redirection
after owner creation fails.
2024-04-27 11:02:50 +02:00
Girish Ramakrishnan
4e39eb89fd const 2024-04-27 10:48:23 +02:00
Girish Ramakrishnan
a783944700 notfound: better error message for IP 2024-04-26 21:25:33 +02:00
Girish Ramakrishnan
8a987db177 provision: add route to detect ipv4 and ipv6 2024-04-26 20:53:32 +02:00
Girish Ramakrishnan
834a7d0f55 rename setupdns to setup 2024-04-26 20:32:23 +02:00
Girish Ramakrishnan
051bcb7819 rename setup to activation 2024-04-26 20:26:57 +02:00
Girish Ramakrishnan
126587ba82 lint: constness 2024-04-26 20:09:36 +02:00
Girish Ramakrishnan
860ebcbe6a provision: add activation guard 2024-04-26 20:06:56 +02:00
Girish Ramakrishnan
25f395ed63 Update DNS A record text 2024-04-26 19:13:34 +02:00
Girish Ramakrishnan
2da361a1f2 waitfordns: resolve and check against NS' IPv6 address 2024-04-26 19:12:53 +02:00
Johannes Zellner
4e363dc77a frontend: move more UI elements to pankow 2024-04-26 17:11:02 +02:00
Girish Ramakrishnan
23e20b9b83 waitfordns: better debugs 2024-04-26 14:46:01 +02:00
Girish Ramakrishnan
e70a6ffbb9 zoneName filter is gone 2024-04-26 14:25:02 +02:00
Girish Ramakrishnan
cab236123f reindent branding page 2024-04-26 14:10:12 +02:00
Johannes Zellner
cab7e0d8a3 Fixup indentation in setup pages 2024-04-26 14:07:53 +02:00
Girish Ramakrishnan
2f425f8119 provision: add ipv6 config 2024-04-26 12:20:15 +02:00
Girish Ramakrishnan
017e46fa0f rename sysinfo to ipv4Config 2024-04-26 12:20:15 +02:00
Johannes Zellner
9efcd9060e frontend: Use pankow breadcrumbs 2024-04-25 19:35:54 +02:00
Girish Ramakrishnan
abdd5d3e0e eslint: upgrade 2024-04-25 19:00:37 +02:00
Girish Ramakrishnan
cf40346e1a eslint: add node globals 2024-04-25 18:26:35 +02:00
Girish Ramakrishnan
b6d80fb443 eslint.config.js for the new eslint 2024-04-25 18:14:06 +02:00
Girish Ramakrishnan
f6e4f1aefc network: ipv4 can be disabled 2024-04-25 15:50:42 +02:00
Girish Ramakrishnan
dbf66b8e89 fix indent 2024-04-25 15:06:17 +02:00
Girish Ramakrishnan
53ad3902ac remove unused function 2024-04-25 15:06:17 +02:00
Girish Ramakrishnan
cae2bfbdc2 domains: add desec provider 2024-04-24 21:29:42 +02:00
Girish Ramakrishnan
58d6142460 ovh: storage location has changed 2024-04-24 16:37:41 +02:00
Johannes Zellner
2ca4838ac7 dashboard: app config has new info tab 2024-04-23 17:07:30 +02:00
Girish Ramakrishnan
3787f90283 appstore: bump timeout to 60s instead of 30s
this timeout is hit on some servers (which have some networking
issue). unfortunately, this triggers a bug in superagent -
https://github.com/ladjs/superagent/issues/1801
2024-04-23 11:41:51 +02:00
Girish Ramakrishnan
9064375e25 cloudron-support: remove bad nginx configs 2024-04-23 10:00:06 +02:00
Girish Ramakrishnan
033036bd1a cloudron-support: check service uptime 2024-04-22 17:45:43 +02:00
Girish Ramakrishnan
5d74d80829 cloudron-support: check if node binary exists 2024-04-22 16:41:26 +02:00
Girish Ramakrishnan
88231e3d35 sftp: add rate limit 2024-04-21 21:04:00 +02:00
Girish Ramakrishnan
1aa683aeab add comments on the rate limits 2024-04-21 21:02:55 +02:00
Girish Ramakrishnan
c2326bc5cc oidc: add rate limit for login requests 2024-04-21 20:58:12 +02:00
Girish Ramakrishnan
55db3ae517 Fix link 2024-04-21 16:48:40 +02:00
Johannes Zellner
4b0dbf0183 dashboard: localstorage has no concept of booleans 2024-04-20 22:02:05 +02:00
Johannes Zellner
2725e001a5 frontend: update dependencies 2024-04-20 14:10:34 +02:00
Johannes Zellner
02a0f65e4b dashboard: update fontawesome and sass 2024-04-20 13:41:04 +02:00
Johannes Zellner
9fd964022e dashboard: html-templates is gone 2024-04-20 13:38:47 +02:00
Johannes Zellner
ec7dabc1c7 oidc: also allow login on aliased app domains 2024-04-19 19:03:23 +02:00
Girish Ramakrishnan
95eeb9ce93 s/your/the 2024-04-19 18:33:17 +02:00
Girish Ramakrishnan
d137cdf881 update cron module
CronJob -> CronJob.from
CronJob(time) -> CronTime
2024-04-19 18:31:47 +02:00
Girish Ramakrishnan
a926a3e8a8 update google cloud modules
https://github.com/googleapis/nodejs-storage/releases/tag/v7.0.0
2024-04-19 18:09:17 +02:00
Girish Ramakrishnan
e8b3516d34 update marked 2024-04-19 18:00:02 +02:00
Girish Ramakrishnan
54e5e0cb7e update commander
https://github.com/tj/commander.js/releases/tag/v12.0.0
2024-04-19 17:56:15 +02:00
Girish Ramakrishnan
baa4620523 update jsdom
https://github.com/jsdom/jsdom/releases/tag/24.0.0
2024-04-19 17:53:26 +02:00
Girish Ramakrishnan
fcd1532a4d update jose
breaking changes: https://github.com/panva/jose/releases/tag/v5.0.0
2024-04-19 17:45:26 +02:00
Girish Ramakrishnan
66b768b176 Update packages 2024-04-19 17:40:42 +02:00
Girish Ramakrishnan
eeae8c92d0 nodejs: update to 20.12.2 2024-04-19 17:40:42 +02:00
Johannes Zellner
d35bfbb0fd dashboard: finish checklist display
pending showing acknowledged items later
2024-04-19 14:32:34 +02:00
Johannes Zellner
4516b0c57c Do not return but continue in a loop 2024-04-19 14:29:41 +02:00
Johannes Zellner
49243822af dashboard: show app checklist 2024-04-19 14:17:54 +02:00
Johannes Zellner
16521d5434 Fix updateChecklist usage 2024-04-19 12:15:13 +02:00
Girish Ramakrishnan
1afa2e87ec mailserver: a056bcfd broke mail server restart
after proxying, we never restarted the mail server

also add note that restart has to reconfigure
2024-04-19 10:48:08 +02:00
Girish Ramakrishnan
18ec929501 lint 2024-04-19 10:48:08 +02:00
Johannes Zellner
7d6636bb54 Only add checklist items if they apply due to sso state 2024-04-18 16:05:38 +02:00
Johannes Zellner
3c7e6b59f0 Add initial support for apps.checklist 2024-04-17 16:54:54 +02:00
Johannes Zellner
daa8a60da2 oidc: Inject currently hardcoded CLOUDRON_OIDC_PROVIDER_NAME env var
This is designed to be used in the packages for the login button:
"Login with ${CLOUDRON_OIDC_PROVIDER_NAME}"
2024-04-17 15:06:22 +02:00
Johannes Zellner
f231d51d0b Make oidc authproxy login button translatable 2024-04-17 14:21:07 +02:00
Girish Ramakrishnan
308f315ed5 troubleshoot: print box version 2024-04-17 09:26:32 +02:00
Girish Ramakrishnan
a572374ad7 updatechecker: deep compare update object from appstore
When 'changelog' , 'unstable' fields change the box code is not
getting it.
2024-04-16 19:30:14 +02:00
Girish Ramakrishnan
1cf315634c appstore: check the type of unstable field 2024-04-16 19:19:27 +02:00
Johannes Zellner
b0d2bdbad9 Make it login with cloudron in authproxy 2024-04-16 14:56:18 +02:00
Johannes Zellner
255fb0cac0 proxyauth: show intermediate login button page 2024-04-16 13:43:12 +02:00
Johannes Zellner
c3be0018fe proxyauth: send user to oidc login instead of /login 2024-04-16 11:29:00 +02:00
Girish Ramakrishnan
37e2269387 import: add seal option 2024-04-15 22:20:04 +02:00
Girish Ramakrishnan
5dbe2ce2e4 cifs: enable seal by default 2024-04-15 22:00:28 +02:00
Johannes Zellner
1008ec4fa1 proxyauth: remove basic auth login form 2024-04-15 18:52:07 +02:00
Johannes Zellner
d36d1cf1da dashboard: wait on refreshApp on submitting notes 2024-04-15 17:38:02 +02:00
Johannes Zellner
21d7438bbe proxyauth: user OpenID instead of basic auth 2024-04-15 15:59:16 +02:00
Girish Ramakrishnan
caf1c37171 motd: mention troubleshooting tool 2024-04-15 13:46:44 +02:00
Girish Ramakrishnan
0a748ac78a better AVX error message 2024-04-15 10:10:13 +02:00
Johannes Zellner
76c4002a04 oidc: Add profile picture claim 2024-04-14 12:05:45 +02:00
Johannes Zellner
201a07f717 dashboard: Some dark mode fixes for list view 2024-04-12 19:51:46 +02:00
Johannes Zellner
5b2eb51511 dashboard: show app count in list view 2024-04-12 14:12:03 +02:00
Johannes Zellner
36ab5800a3 oidc: enable CORS for internal apps 2024-04-11 19:10:29 +02:00
Girish Ramakrishnan
a79486275e tldjs: update rules using --tldjs-update-rules
the rules we use are 6 years old! we still need to use the public
suffix list to figure out the zone name by default for ease of use.

Domains like co.uk will only appear in the suffix list and not in the
tld list (https://www.iana.org/domains/root/db)

To verify if the list is updated:

node -e "console.log(require('tldjs').getDomain('whatever.framer.ai'))"

The above will output "whatever.framer.ai"
2024-04-11 18:28:52 +02:00
Girish Ramakrishnan
6dc70a8f3b dashboard: tld and angular-tld are not used 2024-04-11 18:08:21 +02:00
Johannes Zellner
8e990e4e0a dashboard: Set app info as default configure tab 2024-04-11 13:45:34 +02:00
Girish Ramakrishnan
f11becfcc8 async'ify
crazy this has gone unnoticed for so long!
2024-04-10 18:52:39 +02:00
Johannes Zellner
8d04374764 dashboard: info tab translations 2024-04-10 18:48:20 +02:00
Johannes Zellner
87ae95aa4f Add per-app notes feature 2024-04-10 18:34:58 +02:00
Girish Ramakrishnan
0fa1ec44b1 app: add description for memory 2024-04-10 18:28:32 +02:00
Girish Ramakrishnan
b4e4f26361 Rework cpuShares into cpuQuota
cpuShares is the relative weight wrt other apps. This is used when
there is contention for CPU. If we want this, maybe we implement
a UI where we show all the apps and let the user re-order them.
As it stands, it is confusing.

cpuQuota is a more straightforward "hard limit" of the CPU% that you
want the app to consume.

Can be tested with : stress -c 8 -t 20s
2024-04-10 18:25:14 +02:00
Girish Ramakrishnan
2afaf1f36d more changes 2024-04-10 12:52:42 +02:00
Girish Ramakrishnan
f236213356 backups: memory max is RAM 2024-04-10 12:48:07 +02:00
Girish Ramakrishnan
efd0be5e2c services: send the default memory limit 2024-04-10 12:42:25 +02:00
Johannes Zellner
6612f48d0a dashboard: make filter bar persistent and inline instead of popover 2024-04-10 12:24:56 +02:00
Girish Ramakrishnan
f1679f1614 compute app excess based on RAM*2 2024-04-10 12:12:49 +02:00
Girish Ramakrishnan
8b7dca00af app memory: make slider go till RAM
anything above RAM is useless
2024-04-10 12:12:49 +02:00
Johannes Zellner
59fa26b0fb dashboard: we hardly use warning button colour 2024-04-09 19:55:47 +02:00
Johannes Zellner
7a92222050 dashboard: show active filter numbers 2024-04-09 19:55:07 +02:00
Girish Ramakrishnan
be2775e12e memoryLimit: redefine to not include swap
Currently, we allocate 50% as RAM and 50% as swap. The manifest is
usually quite conservative on memory values. This means that we set
up a system where the app is applying memory pressure almost immediately.
This then swaps things randomly and increases cpu usage (kswapd shows
up in the profile).

To rethink the whole situation: we should not cap apps with a swap limit at all.
The memory hard limit is what is important. By redefining memoryLimit , we are
doubling every container's memory and it's good that we over allocate this.
2024-04-09 18:59:40 +02:00
Girish Ramakrishnan
6c3f8b9b84 various changes 2024-04-09 18:48:46 +02:00
Johannes Zellner
f02157857c dashboard: add / eventhandler for search 2024-04-09 15:41:50 +02:00
Girish Ramakrishnan
470b0d6be7 update some modules 2024-04-09 15:31:46 +02:00
Girish Ramakrishnan
2b1b304c6e backup/import/restore: fix crash with root path calcuation
rootPath was calculated before the arguments were validated
2024-04-09 13:53:48 +02:00
Johannes Zellner
5460a64951 dashboard: Make app list columns sortable 2024-04-09 13:51:57 +02:00
Girish Ramakrishnan
62faf616c5 import: acceptSelfSignedCerts is validated at provider 2024-04-09 13:24:33 +02:00
Girish Ramakrishnan
3f2f4c7c6b restore: acceptSelfSignedCerts is validated by provider 2024-04-09 13:20:01 +02:00
Girish Ramakrishnan
5e49a33e8f backups: rootPath is needed only when testing storage 2024-04-09 13:03:31 +02:00
Girish Ramakrishnan
5fb7d53018 backups: encryptedFilenames and mountOptions are validated at provider level 2024-04-09 12:31:10 +02:00
Girish Ramakrishnan
424a3c2b53 validateEncryptionPassword need not by exported or async 2024-04-09 12:23:43 +02:00
Girish Ramakrishnan
6e629b984b typo in error message 2024-04-09 11:53:58 +02:00
Girish Ramakrishnan
c73609211a import: fix typo in mountPoint parameter
mountpoint provider supports prefix (except not via UI). It's more
natural for the user to enter the actual mountpoint than the filesystem
path directly.
2024-04-08 19:21:59 +02:00
Johannes Zellner
e5477351f8 dashboard: do not specify tooltip location in list view 2024-04-08 17:57:59 +02:00
Johannes Zellner
d89f8d99a3 dashboard: only show relevant actions in list view 2024-04-08 16:44:15 +02:00
Johannes Zellner
da472dff19 dashboard: use new image edit indicator in apps and applinks configuration 2024-04-08 16:28:38 +02:00
Johannes Zellner
2dc501dcbd dashboard: clear user selection when adding groups 2024-04-08 12:55:54 +02:00
Johannes Zellner
052b705c3c dashboard: preserve apps view type in localStorage 2024-04-06 16:16:48 +02:00
Johannes Zellner
24c8fca971 Better mobile list view and display app task progress 2024-04-06 16:12:08 +02:00
Johannes Zellner
86edabee4d Some visual improvements to the list view 2024-04-06 15:47:46 +02:00
Johannes Zellner
d6f162a8ca dashboard: add initial version of app list view 2024-04-06 12:30:44 +02:00
Johannes Zellner
9e05a4eab7 Show background in all oidc pages 2024-04-06 10:52:25 +02:00
Johannes Zellner
32d9490856 Revert "dashboard: first use profile background if not exist try branding background"
This reverts commit 8db6da2de9.
2024-04-06 10:00:16 +02:00
Johannes Zellner
91d9f66eb8 dashboard: max-height is wrong here 2024-04-05 20:03:52 +02:00
Johannes Zellner
86986d8f34 Allow img-src blob: 2024-04-05 19:59:38 +02:00
Johannes Zellner
03ef9f109f dashboard: better image upload/edit indicator 2024-04-05 17:37:58 +02:00
Johannes Zellner
67a8228886 Show placeholder image for branding background 2024-04-05 17:15:31 +02:00
Johannes Zellner
8db6da2de9 dashboard: first use profile background if not exist try branding background 2024-04-05 17:11:37 +02:00
Johannes Zellner
544b8180b2 dashboard: add UI to change background image 2024-04-05 16:26:59 +02:00
Johannes Zellner
2515b032d0 Add branding background UI 2024-04-05 14:31:41 +02:00
Girish Ramakrishnan
6086b0e797 typo 2024-04-05 12:11:43 +02:00
Girish Ramakrishnan
2760e25c0f users: validate groupIds items 2024-04-05 11:59:16 +02:00
Girish Ramakrishnan
76aa0b4a70 add to changes 2024-04-04 18:25:35 +02:00
Girish Ramakrishnan
0e23687c7f cloudron-setup: lower memory requirement further for lightsail 2024-04-04 17:51:27 +02:00
Johannes Zellner
028b820d48 oidc: Reload the login view if session is gone 2024-04-04 17:32:58 +02:00
Johannes Zellner
2c81458954 Show branding background image in login view 2024-04-04 15:38:44 +02:00
Johannes Zellner
ebe1883f8e Also trigger first time oidc auto login flow for initial admin creation 2024-04-04 11:42:57 +02:00
Girish Ramakrishnan
030e468829 docker: prune volumes on infra change 2024-04-04 11:36:26 +02:00
Johannes Zellner
68724bcb4f Revert "oidc: enable rpInitiated logout"
This reverts commit a6f4b2896a.
2024-04-04 10:41:00 +02:00
Johannes Zellner
6186bb54e4 Revert "oidc: allow post logout redirect back to the app"
This reverts commit 3ddf72a24d.
2024-04-04 10:40:53 +02:00
Johannes Zellner
a4e822dec2 Make autologin token only one-time use 2024-04-04 10:29:36 +02:00
Johannes Zellner
5744cb7318 auto login from activation 2024-04-04 10:26:48 +02:00
Johannes Zellner
2f6a66dbd7 oidc: enable auto login when a token is provided 2024-04-03 18:11:21 +02:00
Johannes Zellner
91d3980e3b Add cloudron background branding apis 2024-04-03 17:27:22 +02:00
Johannes Zellner
3ddf72a24d oidc: allow post logout redirect back to the app 2024-04-03 15:49:03 +02:00
Johannes Zellner
a6f4b2896a oidc: enable rpInitiated logout 2024-04-02 20:38:12 +02:00
Johannes Zellner
c79ddbf948 dashboard: attempt to use firefox background color 2024-04-02 17:55:08 +02:00
Girish Ramakrishnan
de99b8ecce Fix AVX support edge cases
* Always show restart button. When using a local VM, you can dynamically
switch flags. So, let the user rebuild. Show error if we cannot.
* The logs button is an "a" tag which is clickable despite ng-disabled
2024-04-01 23:05:20 +02:00
Girish Ramakrishnan
8b0bcde7ec cloudflare: result is now null and not empty array 2024-04-01 17:58:40 +02:00
Girish Ramakrishnan
d862f1f5b4 cloudflare: fix crash when result is null 2024-04-01 17:31:20 +02:00
Girish Ramakrishnan
1c4f6315a6 mongodb: optional avx support in service routes 2024-04-01 17:31:20 +02:00
Girish Ramakrishnan
44eaac6685 cloudron-setup: add warning when installing with no avx 2024-04-01 17:31:20 +02:00
Johannes Zellner
a89576965d Revert to lighter background 2024-04-01 12:42:44 +02:00
Girish Ramakrishnan
774f14327c addons: optional start mongodb based on AVX 2024-03-30 19:20:24 +01:00
Girish Ramakrishnan
6bd9391160 syslog: fix tests 2024-03-30 19:17:28 +01:00
Girish Ramakrishnan
a82fb0c2cb typo from 110e68331 2024-03-30 19:17:28 +01:00
Girish Ramakrishnan
110e683318 rename checkManifestConstraints function 2024-03-30 18:25:37 +01:00
Girish Ramakrishnan
781ee77280 services: remove docker dynamic env hook 2024-03-30 18:25:37 +01:00
Johannes Zellner
adc9894fde Use a darker gray background 2024-03-29 17:05:46 +01:00
Johannes Zellner
c7bf5f2abc dashboard: sync list hover background with main background 2024-03-28 19:24:45 +01:00
Johannes Zellner
601e868afc dashboard: more font improvements 2024-03-28 17:22:17 +01:00
Johannes Zellner
25b1259c4c dashboard: use noto-sans instead of the dated Roboto 2024-03-28 17:03:53 +01:00
Johannes Zellner
1a8a111c79 dashboard: freshenup background, navbar and footer colors 2024-03-28 15:25:03 +01:00
Girish Ramakrishnan
497b3016c0 7.7.2 changes 2024-03-27 10:12:37 +01:00
Johannes Zellner
fe9bd52b04 frontend: make uploads cancellable 2024-03-26 09:54:59 +01:00
Johannes Zellner
0705c77333 Frontend: update pankow for pretty fileupload size 2024-03-25 14:56:07 +01:00
Girish Ramakrishnan
b66e77a2d8 Fix crash when system has no swap 2024-03-22 10:39:35 +01:00
Girish Ramakrishnan
4b4c8d8052 7.7.2 changes 2024-03-21 19:11:57 +01:00
Girish Ramakrishnan
4ee56782ba move syslog.js to top level 2024-03-21 19:09:51 +01:00
Girish Ramakrishnan
104997d77c syslog: change it to unix domain socket
docker is using a extra udp port for every container. when there is
a lot of containers, a lot of random udp ports get used up. this causes
problems when installing apps that require contiguous port ranges
2024-03-21 18:59:08 +01:00
Girish Ramakrishnan
8e07b3c96d remove unused variable 2024-03-21 17:11:17 +01:00
Johannes Zellner
4e618540f8 dashboard: preserve app link paths 2024-03-18 11:40:17 +01:00
Girish Ramakrishnan
49941a34b9 backups: deleted apps must also be displayed in contents 2024-03-14 16:14:50 +01:00
Johannes Zellner
771b797a23 frontend: update dependencies to fix filemanager empty folder content layout 2024-03-13 11:42:47 +01:00
Girish Ramakrishnan
d09915bf6e scheduler: typo
(cherry picked from commit 09e00e6d58)
2024-03-12 18:06:24 +01:00
Johannes Zellner
264c94ff34 dashboard: remove bootstrap slider component 2024-03-12 17:33:38 +01:00
Johannes Zellner
a90df99331 dashboard: migrate rsync concurrency settings to native range slider 2024-03-12 17:31:07 +01:00
Johannes Zellner
78f0d61627 dashboard: make backup upload part size steps explicit with native widget 2024-03-12 17:09:35 +01:00
Johannes Zellner
8c106b3435 dashboard: replace old slider with native widget 2024-03-12 16:44:08 +01:00
Johannes Zellner
42555c7231 dashboard: use native slider for mailbox storage quota 2024-03-12 15:43:08 +01:00
Johannes Zellner
ab035a2afe dashboard: use native slider for mail size 2024-03-12 15:35:20 +01:00
Johannes Zellner
3a30eed3cd dashboard: remove commented slider 2024-03-12 15:29:30 +01:00
Johannes Zellner
4cb390374b dashboard: use native range slider for services 2024-03-12 15:28:47 +01:00
Girish Ramakrishnan
50179dd7eb 7.7.1 changes 2024-03-12 11:28:27 +01:00
Girish Ramakrishnan
2956c3360c postgresql: fix whitelist ext loading 2024-03-12 11:27:42 +01:00
Girish Ramakrishnan
c634bdbd34 scheduler: do not create jobs of suspended apps
otherwise, when an app is uninstalling, it creates the docker containers
by calling getDynamicEnvironment. This ends up adding addonConfigs for the
docker addon and prevents the app from getting uninstalled.
2024-03-12 00:55:06 +01:00
Johannes Zellner
1892c0cd80 dashboard: use native slider element for app memory and cpu 2024-03-11 21:36:18 +01:00
Johannes Zellner
63b395982c dashboard: use less gulp processing for css turns out it actually made the files much larger 2024-03-11 19:03:42 +01:00
Johannes Zellner
d50c8539b2 dashboard: update dependencies 2024-03-11 18:49:30 +01:00
930 changed files with 18741 additions and 38486 deletions

View File

@@ -1,25 +0,0 @@
{
"env": {
"node": true,
"es6": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 13
},
"rules": {
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"no-console": "off"
}
}

3
.gitignore vendored
View File

@@ -1,7 +1,4 @@
node_modules/
coverage/
.nyc_output/
webadmin/dist/
installer/src/certs/server.key
# vim swap files

24
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,24 @@
run_tests:
stage: test
image: cloudron/base:4.2.0@sha256:46da2fffb36353ef714f97ae8e962bd2c212ca091108d768ba473078319a47f4
services:
- name: mysql:8.0
alias: mysql
variables:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: box
BOX_ENV: ci
DATABASE_URL: mysql://root:password@mysql/box
script:
- echo "Running tests..."
- mysql -hmysql -uroot -ppassword -e "ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'password';"
- mysql -hmysql -uroot -ppassword -e "CREATE DATABASE IF NOT EXISTS box"
- npm install
- node_modules/.bin/db-migrate up
- ln -s /usr/local/node-18.18.0/bin/node /usr/bin/node
- node_modules/.bin/mocha --no-timeouts --bail src/test/tokens-test.js
- echo "Done!"
stages:
- test

View File

@@ -1,5 +0,0 @@
{
"node": true,
"unused": true,
"esversion": 11
}

169
CHANGES
View File

@@ -2753,3 +2753,172 @@
* Fix streaming of logs with `logPaths`
* profile: store user language setting in the database
[7.7.1]
* postgresql: fix bug in loading of contrib extensions
* dashboard: use native slider element for app memory and cpu
[7.7.2]
* docker: use unix domain socket based logging instead of udp
* dashboard: use native slider element for app memory and cpu
* filemanager: fix empty folder content layout
* dashboard: preserve app link paths
* backups: deleted apps must also be displayed in contents
* filemanager: make uploads cancellable
* Fix crash on systemds with no swap
[8.0.0]
* mongodb: optionally start mongodb based on AVX support
* dashboard: font and color improvements
* docker: prune volumes on infra change
* oidc: initial login of admin and normal user now gets an OIDC session
* branding: default background image for the dashboard
* dashboard: list view for apps
* import: fix crash when using mountpoint provider
* dashboard: set '/' as keyboard shortcut
* app: memory limit is redefined to be just RAM and unlimited swap
* dashboard: rework filter UI
* cpu: rework cpu shares into cpu quota
* cifs: enable seal encryption by default
* updatechecker: fix bug where release info was not refreshed
* ovh: storage location domain has changed. add rbx region
* domains: add deSEC integration
* notfound: better message when navigating by IP address
* IPv6 only server installation
* Initial Ubuntu 24.04 (Noble Numbat) support
* syslog: handle potential multiline syslog input
* user directory: fixes to mandatory 2fa setting when cloudron connector is used
* notification: do not send login notification for external users
* dashboard: pending checklist indicator
* cloudron-support: add --recreate-docker and --recreate-container
* filemanager: add dark mode
* proxyauth: now uses oidc instead of ldap auth
* dashboard: add admin notes
* Use systemd-resolved as the system resolver. unbound is now only for mail server and recursive DNS lookups
[8.0.1]
* nfs: disable rpcbind service. we only support nfsv4 mounting
* dashboard: only show postinstall if notes are not just empty
* ami: disable route53
* mailer: add html version of test mail
* sshfs: server side copying
* backups: rewrite tgz backups using tar-stream
* backups: fix issue with s3 backend where files missing in remote was not detected correctly
* provision: redirect to correct task (setup/restore/activation)
[8.0.2]
* tgz: fix unhandled promise error handler
* tgz: add underflow/overflow proxy stream to ensure size of a changing file
* backups: give task a low oomScoreAdjust to not get killed
* Fix issue with uploads via File Manager where temp files were not cleaned up
* addons: fix crash when importing database of an app with no addons
* sshfs: if remote copy fails, fallback to sshfs based copy
* frontend: reduce DOM node creation on very fast logstreams and cap to 1k loglines
[8.0.3]
* logs: fix recursion when displaying box logs
* frontend: fix clear view in logs viewer
* dashboard: support links/markdown in checklist items
[8.0.4]
* ami: IMDv2 support
* ionos: add contract-owned eu-central-3
* dashboard: remove mailbox import/export feature
* backupcleaner: do not remove the backup in progress
* backups: make noop upload work again
* volumes: `/mnt/volumes` is reserved
* apps: do not log app logs to output
* sftp: restore mode and owner
* dashboard: also render checklist items in apps.html
[8.0.5]
* cpu quota: fix rounding error
* frontend: fix translation resolver to actually fallback to english
* i18n: fix crash if language file is missing
* memory: fix slider UI where max was incorrectly set
* digitalocean: add LON1 Spaces region
* exoscale: add sos AT-VIE-2 region
* i18n: remove use of "Cloudron"
* tz: add note in backup and update UI
* backups: do not overflow the schedule timings
* checklist: new checklist items on update are acknowledged
* backups: automatically trigger a remount if mount is not active
* logs: rework the syslog parser
* docker: use system dns for app containers
* logs: show error message in UI when log rotated
* unbound: prefer ip4 for dns queries (only on ubuntu 24 and above)
* apps: allow operators to update apps
[8.0.6]
* Fix AdGuard resolving dashboard to docker bridge IP
[8.1.0]
* backups: add hetzner object storage
* registry: cloudron container registry
* gandi: add PAT token support
* OpenID: add groups claim support
* OpenID: enable refresh token support (dokuwiki)
* filemanger: fix various regressions
* dashboard: mobile and dark-mode fixes
* syslog: fix multiline timestamps
* porkbun: use new API endpoint
* fix "happy eyeballs" quirk in nodejs
* Update nodejs to 20.18.0
[8.2.0]
* rsync: show better error message with too many empty dirs, symlinks or executables
* mail: update Solr to 8.11.4
* mail: update Haraka to 3.0.5
* Add sqlite3 addon
* docker: update docker to 27.3.1
* du: add exclude file to skip filesystem usage checks
* mail: attachment search
* oidc: use cloudron name as provider name
* groups: add eventlog
* resources: allow mounting devices into apps
* remove global lock
* hetzner: add helsinki object storage location
* backups: implement app archive
* notifications: per user email notification config
* postgres: enable vector extension
* docker: fallback to downloading images from quay if dockerhub does not work
[8.2.1]
* apps: fix bug where update and notes indicator was shown to normal users
* archive: disable archiving for pre-8.2 backups. we don't have enough info to unarchive
* dashboard: fix browser caching issue
[8.2.2]
* gandi: add token type in the setup view
* mail: fix issue with dkim signing
* mail: fix crash in dns list plugin
* scheduler: create jobs with cloudron tz setting
* security: fix issue where '/' symlink allows admins to get ssh access
[8.2.3]
* mail: give container a static IP
* firewall: add masquerading rules for containers to reach each other via public IP
* docker: fix parsing of optional namespace in image refs
[8.2.4]
* restore: fix crash with invalid backup id
* setup: add inwx to dns setup
* backups: add preserve attributes checkbox
* mail: add ipv6 rdns check
* mail: disable OCR in tika. this is too slow
* mail: rebuild index script
* backups: add preserve attributes checkbox
* username: only ending with .app is reserved
* cloudron-support: add helper function to free up disk space when full
* cloudflare: list API does not return `zone_id` anymore
[8.3.0]
* new base image: cloudron/base:5.0.0@sha256:04fd70dbd8ad6149c19de39e35718e024417c3e01dc9c6637eaf4a41ec4e596c
* Database upgrades are automatically performed. This might take some time depending on the amount of data.
* Postgres v16
* Mongodb v7
* PHP v8.3
* Node.js v22 LTS
[8.3.1]
* Fix crash in postgresql pgvector extension

View File

@@ -45,20 +45,19 @@ Try our demo at https://my.demo.cloudron.io (username: cloudron password: cloudr
[Install script](https://docs.cloudron.io/installation/) - [Pricing](https://cloudron.io/pricing.html)
**Note:** This repo is a small part of what gets installed on your server - there is
the dashboard, database addons, graph container, base image etc. Cloudron also relies
on external services such as the App Store for apps to be installed. As such, don't
clone this repo and npm install and expect something to work.
**Note:** This repo is just a part of what gets installed on the server. Database addons,
Mail Server, Stat contains etc are not part of this repo. As such, don't clone this repo and
npm install and expect something to work.
## License
Please note that the Cloudron code is under a source-available license. This is not the same as an
open source license but ensures the code is available for introspection (and hacking!).
open source license but ensures the code is available for transparency and introspection (and hacking!).
## Contributions
Just to give some heads up, we are a bit restrictive in merging changes. We are a small team and
would like to keep our maintenance burden low. It might be best to discuss features first in the [forum](https://forum.cloudron.io),
We are very restrictive in merging changes. We are a small team and would like to keep our maintenance burden low,
not to mention legal issues. It might be best to discuss features first in the [forum](https://forum.cloudron.io),
to also figure out how many other people will use it to justify maintenance for a feature.
# Localization

12
box.js
View File

@@ -5,6 +5,7 @@
const constants = require('./src/constants.js'),
fs = require('fs'),
ldapServer = require('./src/ldapserver.js'),
net = require('net'),
oidc = require('./src/oidc.js'),
paths = require('./src/paths.js'),
proxyAuth = require('./src/proxyauth.js'),
@@ -25,9 +26,17 @@ async function setupLogging() {
};
}
// happy eyeballs workaround. when there is no ipv6, nodejs timesout prematurely since the default for ipv4 is just 250ms
// https://github.com/nodejs/node/issues/54359
async function setupNetworking() {
net.setDefaultAutoSelectFamilyAttemptTimeout(2500);
}
// this is also used as the 'uncaughtException' handler which can only have synchronous functions
function exitSync(status) {
if (status.error) fs.write(logFd, status.error.stack + '\n', function () {});
const ts = new Date().toISOString();
const msg = status.error.stack.replace(/\n/g, `\n${ts} `); // prefix each line with ts
if (status.error) fs.write(logFd, `${ts} ${msg}\n`, function () {});
fs.fsyncSync(logFd);
fs.closeSync(logFd);
process.exit(status.code);
@@ -35,6 +44,7 @@ function exitSync(status) {
async function startServers() {
await setupLogging();
await setupNetworking();
await server.start(); // do this first since it also inits the database
await proxyAuth.start();
await ldapServer.start();

View File

@@ -1,6 +0,0 @@
# following files are skipped when exporting using git archive
test export-ignore
docs export-ignore
.gitattributes export-ignore
.gitignore export-ignore

13
dashboard/.gitignore vendored
View File

@@ -1,11 +1,16 @@
dist/
node_modules/
# will get generated on build
public/theme.css
public/theme.css.map
# vim swap files
*.swp
# these are not done yet
src/translation/ja.json
src/translation/pl.json
src/translation/si.json
src/translation/gl.json
public/translation/ja.json
public/translation/pl.json
public/translation/si.json
public/translation/gl.json
public/translation/hr.json

View File

@@ -1,20 +0,0 @@
{
"node": true,
"browser": true,
"unused": true,
"esversion": 6,
"globalstrict": false,
"predef": [
"$",
"angular",
"async",
"describe",
"it",
"before",
"after",
"require",
"monaco",
"Mimer",
"ISTATES"
]
}

View File

@@ -1,35 +0,0 @@
The Cloudron Subscription license
Copyright (c) 2022 Cloudron UG
With regard to the Cloudron Software:
This software and associated documentation files (the "Software") may only be
used in production, if you (and any entity that you represent) have agreed to,
and are in compliance with, the Cloudron Subscription Terms of Service, available
at https://cloudron.io/legal/terms.html (the “Subscription Terms”), or other
agreement governing the use of the Software, as agreed by you and Cloudron,
and otherwise have a valid Cloudron Subscription. Subject to the foregoing sentence,
you are free to modify this Software and publish patches to the Software. You agree
that Subscription and/or its licensors (as applicable) retain all right, title and
interest in and to all such modifications and/or patches, and all such modifications
and/or patches may only be used, copied, modified, displayed, distributed, or otherwise
exploited with a valid Cloudron subscription. Notwithstanding the foregoing, you may copy
and modify the Software for development and testing purposes, without requiring a
subscription. You agree that Cloudron and/or its licensors (as applicable) retain
all right, title and interest in and to all such modifications. You are not
granted any other rights beyond what is expressly stated herein. Subject to the
foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
and/or sell the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
For all third party components incorporated into the Cloudron Software, those
components are licensed under the original license provided by the owner of the
applicable component.

View File

@@ -1,20 +0,0 @@
# Cloudron Dashboard
This is the front end code of Cloudron. The backend code is [here](https://git.cloudron.io/cloudron/box).
## Developing
* `npm install`
* `gulp develop --api-origin=https://my.example.com`
## License
Please note that the Cloudron code is under a source-available license. This is not the same as an
open source license but ensures the code is available for inspection (and hacking!).
## Contributions
Just to give a heads-up, we are a bit restrictive in merging changes. We are a small team and
would like to keep our maintenance burden low. It might be best to first discuss features in the [forum](https://forum.cloudron.io),
which also helps to determine how many other people will use it to justify maintenance for a feature.

View File

@@ -1,51 +1,49 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />
<meta charset="utf-8" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />
<title>Cloudron Setup</title>
<meta name="description" content="Cloudron Setup">
<title>Cloudron Setup</title>
<meta name="description" content="Cloudron Setup">
<link id="favicon" href="/api/v1/cloudron/avatar" rel="icon" type="image/png">
<link id="favicon" href="/api/v1/cloudron/avatar" rel="icon" type="image/png">
<!-- Theme CSS -->
<link type="text/css" rel="stylesheet" href="/theme.css">
<!-- contains all thing already using import statement -->
<script type="module" src="./src/modules.js"></script>
<!-- Fontawesome -->
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.css?<%= revision %>"/>
<!-- Theme CSS -->
<link type="text/css" rel="stylesheet" href="./src/theme.scss">
<!-- jQuery-->
<script type="text/javascript" src="/3rdparty/js/jquery.min.js"></script>
<!-- jQuery-->
<script type="text/javascript" src="/js/jquery.min.js"></script>
<!-- async -->
<script type="text/javascript" src="/3rdparty/js/async-3.2.0.min.js"></script>
<!-- async -->
<script type="text/javascript" src="/js/async-3.2.0.min.js"></script>
<!-- Bootstrap Core JavaScript -->
<script type="text/javascript" src="/3rdparty/js/bootstrap.min.js"></script>
<!-- Angularjs scripts -->
<script type="text/javascript" src="/js/angular.min.js"></script>
<script type="text/javascript" src="/js/angular-loader.min.js"></script>
<script type="text/javascript" src="/js/angular-cookies.min.js"></script>
<script type="text/javascript" src="/js/angular-md5.min.js"></script>
<script type="text/javascript" src="/js/angular-ui-notification.js"></script>
<!-- Angularjs scripts -->
<script type="text/javascript" src="/3rdparty/js/angular.min.js"></script>
<script type="text/javascript" src="/3rdparty/js/angular-loader.min.js"></script>
<script type="text/javascript" src="/3rdparty/js/angular-cookies.min.js"></script>
<script type="text/javascript" src="/3rdparty/js/angular-md5.min.js"></script>
<script type="text/javascript" src="/3rdparty/js/angular-ui-notification.js"></script>
<script type="text/javascript" src="/3rdparty/js/autofill-event.js"></script>
<!-- Angular directives for bootstrap https://angular-ui.github.io/bootstrap/ -->
<script type="text/javascript" src="/js/ui-bootstrap-tpls-1.3.3.min.js"></script>
<!-- Angular directives for bootstrap https://angular-ui.github.io/bootstrap/ -->
<script type="text/javascript" src="/3rdparty/js/ui-bootstrap-tpls-1.3.3.min.js"></script>
<!-- Angular translate https://angular-translate.github.io/ -->
<script type="text/javascript" src="/js/angular-translate.min.js"></script>
<script type="text/javascript" src="/js/angular-translate-loader-static-files.min.js"></script>
<script type="text/javascript" src="/js/angular-translate-storage-cookie.min.js"></script>
<script type="text/javascript" src="/js/angular-translate-storage-local.min.js"></script>
<!-- Angular translate https://angular-translate.github.io/ -->
<script type="text/javascript" src="/3rdparty/js/angular-translate.min.js?<%= revision %>"></script>
<script type="text/javascript" src="/3rdparty/js/angular-translate-loader-static-files.min.js?<%= revision %>"></script>
<script type="text/javascript" src="/3rdparty/js/angular-translate-storage-cookie.min.js?<%= revision %>"></script>
<script type="text/javascript" src="/3rdparty/js/angular-translate-storage-local.min.js?<%= revision %>"></script>
<!-- Showdown (markdown converter) -->
<script type="text/javascript" src="/js/showdown-1.9.1.min.js"></script>
<!-- Showdown (markdown converter) -->
<script type="text/javascript" src="/3rdparty/js/showdown-1.9.1.min.js?<%= revision %>"></script>
<!-- Setup Application -->
<script type="text/javascript" src="/js/setup.js"></script>
<!-- Setup Application -->
<script type="text/javascript" src="/js/activation.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/js/client.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/js/utils.js?%VITE_CACHE_ID%"></script>
</head>
@@ -138,7 +136,7 @@
<br/>
<div class="row">
<div class="col-md-12 text-center">
<a class="btn btn-success" href="/">Proceed to Dashboard</a>
<a class="btn btn-success" ng-href="firstTimeLoginUrl">Proceed to Dashboard</a>
</div>
</div>
</div>

View File

@@ -23,7 +23,7 @@
height: 100%;
width: 100%;
text-align: center;
font-family: "Roboto","Helvetica Neue",Helvetica,Arial,sans-serif;
font-family: "Noto Sans", Helvetica, Arial, sans-serif;
line-height: 1.846;
}

View File

@@ -0,0 +1,16 @@
<script>
var tmp = window.location.hash.slice(1).split('&');
tmp.forEach(function (pair) {
if (pair.indexOf('access_token=') === 0) localStorage.token = pair.split('=')[1];
});
var redirectTo = '/';
if (localStorage.getItem('redirectToHash')) {
redirectTo += localStorage.getItem('redirectToHash');
localStorage.removeItem('redirectToHash');
}
window.location.href = redirectTo;
</script>

14
dashboard/build.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
set -eu
echo "=> Create timezones.js"
./scripts/createTimezones.cjs ./public/js/timezones.js
echo "=> Build theme.css for oidc views"
./node_modules/.bin/sass --quiet --pkg-importer=node ./src/theme.scss ./public/theme.css
export VITE_CACHE_ID=$(date +%s)
echo "=> Build the dashboard apps"
./node_modules/.bin/vite build

12
dashboard/develop.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
set -eu
echo "=> Set API origin"
export VITE_API_ORIGIN="${DASHBOARD_DEVELOPMENT_ORIGIN}"
# only really used for prod builds to bust cache
export VITE_CACHE_ID="develop"
echo "=> Run vite locally"
npm run dev

View File

@@ -0,0 +1,22 @@
import globals from 'globals';
import js from '@eslint/js';
import pluginVue from 'eslint-plugin-vue';
export default [
js.configs.recommended,
...pluginVue.configs['flat/essential'],
{
files: ["**/*.js"],
languageOptions: {
globals: {
...globals.browser,
},
ecmaVersion: 13,
sourceType: 'module'
},
rules: {
semi: "error",
"prefer-const": "error"
}
}
];

View File

@@ -5,6 +5,13 @@
<link rel="icon" href="/api/v1/cloudron/avatar" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>File Manager</title>
<style>
@media (prefers-color-scheme: dark) {
body {
background-color: black;
}
}
</style>
</head>
<body>
<div id="app"></div>

View File

@@ -1,220 +0,0 @@
/* jslint node:true */
'use strict';
const argv = require('yargs').argv,
autoprefixer = require('gulp-autoprefixer'),
concat = require('gulp-concat'),
cssnano = require('gulp-cssnano'),
ejs = require('gulp-ejs'),
execSync = require('child_process').execSync,
fs = require('fs'),
gulp = require('gulp'),
sass = require('gulp-sass')(require('sass')),
serve = require('gulp-serve'),
sourcemaps = require('gulp-sourcemaps');
if (argv.help || argv.h) {
console.log('Supported arguments for "gulp develop":');
console.log(' --api-origin <cloudron api uri>');
console.log(' --revision <revision>');
console.log(' --appstore-console-origin <appstore console uri>');
process.exit(1);
}
const revision = argv.revision || '';
let apiOrigin = '';
if (argv.apiOrigin) {
if (argv.apiOrigin.indexOf('https://') === 0) apiOrigin = argv.apiOrigin;
else apiOrigin = 'https://' + argv.apiOrigin;
}
var appstore = {
consoleOrigin: argv.appstoreConsoleOrigin || ''
};
console.log();
console.log('Cloudron API: %s', apiOrigin || 'default');
console.log('Building for revision: %s', revision);
console.log();
console.log('Overriding appstore origin:');
console.log(' Console: %s', appstore.consoleOrigin || 'no');
console.log();
gulp.task('fontawesome', function () {
return gulp.src('node_modules/@fortawesome/fontawesome-free/**/*')
.pipe(gulp.dest('dist/3rdparty/fontawesome/'));
});
gulp.task('bootstrap', function () {
return gulp.src('node_modules/bootstrap-sass/assets/javascripts/bootstrap.min.js')
.pipe(gulp.dest('dist/3rdparty/js'));
});
gulp.task('moment', function () {
return gulp.src('node_modules/moment/min/*')
.pipe(gulp.dest('dist/3rdparty/js'));
});
gulp.task('3rdparty-copy', function () {
return gulp.src([
'src/3rdparty/**/*.js',
'src/3rdparty/**/*.map',
'src/3rdparty/**/*.css',
'src/3rdparty/**/*.otf',
'src/3rdparty/**/*.eot',
'src/3rdparty/**/*.svg',
'src/3rdparty/**/*.gif',
'src/3rdparty/**/*.ttf',
'node_modules/chart.js/dist/chart.umd.js'
]).pipe(gulp.dest('dist/3rdparty/'));
});
gulp.task('3rdparty', gulp.series(['3rdparty-copy', 'moment', 'bootstrap', 'fontawesome']));
// --------------
// JavaScript
// --------------
gulp.task('js-index', function () {
return gulp.src([
'src/js/index.js',
'src/js/client.js',
'src/js/utils.js',
'src/views/*.js'
])
.pipe(ejs({ apiOrigin: apiOrigin, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
.pipe(sourcemaps.init())
.pipe(concat('index.js', { newLine: ';' }))
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist/js'));
});
gulp.task('js-passwordreset', function () {
return gulp.src(['src/js/passwordreset.js', 'src/js/utils.js'])
.pipe(ejs({ apiOrigin: apiOrigin, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
.pipe(sourcemaps.init())
.pipe(concat('passwordreset.js', { newLine: ';' }))
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist/js'));
});
gulp.task('js-setupaccount', function () {
return gulp.src(['src/js/setupaccount.js', 'src/js/utils.js'])
.pipe(ejs({ apiOrigin: apiOrigin, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
.pipe(sourcemaps.init())
.pipe(concat('setupaccount.js', { newLine: ';' }))
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist/js'));
});
gulp.task('js-setup', function () {
return gulp.src(['src/js/setup.js', 'src/js/client.js', 'src/js/utils.js'])
.pipe(ejs({ apiOrigin: apiOrigin, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
.pipe(sourcemaps.init())
.pipe(concat('setup.js', { newLine: ';' }))
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist/js'));
});
gulp.task('js-setupdns', function () {
return gulp.src(['src/js/setupdns.js', 'src/js/client.js', 'src/js/utils.js'])
.pipe(ejs({ apiOrigin: apiOrigin, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
.pipe(sourcemaps.init())
.pipe(concat('setupdns.js', { newLine: ';' }))
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist/js'));
});
gulp.task('js-restore', function () {
return gulp.src(['src/js/restore.js', 'src/js/client.js', 'src/js/utils.js'])
.pipe(ejs({ apiOrigin: apiOrigin, revision: revision, appstore: appstore }, {}, { ext: '.js' }))
.pipe(sourcemaps.init())
.pipe(concat('restore.js', { newLine: ';' }))
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist/js'));
});
gulp.task('js', gulp.series([ 'js-index', 'js-passwordreset', 'js-setupaccount', 'js-setup', 'js-setupdns', 'js-restore' ]));
// --------------
// HTML
// --------------
gulp.task('html-views', function () {
return gulp.src('src/views/**/*.html').pipe(gulp.dest('dist/views'));
});
gulp.task('html-templates', function () {
return gulp.src('src/templates/**/*').pipe(gulp.dest('dist/templates'));
});
gulp.task('html-raw', function () {
return gulp.src('src/*.html').pipe(ejs({ apiOrigin: apiOrigin, revision: revision }, {}, { ext: '.html' })).pipe(gulp.dest('dist'));
});
gulp.task('html', gulp.series(['html-views', 'html-templates', 'html-raw']));
// --------------
// CSS
// --------------
gulp.task('css', function () {
return gulp.src('src/*.scss')
.pipe(sourcemaps.init())
.pipe(sass({ includePaths: ['node_modules/bootstrap-sass/assets/stylesheets/'] }).on('error', sass.logError))
.pipe(autoprefixer())
.pipe(cssnano())
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist'));
});
gulp.task('images', function () {
return gulp.src('src/img/**')
.pipe(gulp.dest('dist/img'));
});
gulp.task('translation', function () {
return gulp.src('src/translation/**')
.pipe(gulp.dest('dist/translation'));
});
gulp.task('timezones', function (done) {
execSync('./scripts/createTimezones.js ./dist/js/timezones.js');
done();
});
// --------------
// Utilities
// --------------
gulp.task('clean', function (done) {
fs.rm('dist', { recursive: true, force: true }, done);
});
gulp.task('default', gulp.series(['clean', 'html', 'js', 'timezones', '3rdparty', 'translation', 'images', 'css']));
gulp.task('watch', function (done) {
gulp.watch(['src/*.scss'], gulp.series(['css']));
gulp.watch(['src/img/*'], gulp.series(['images']));
gulp.watch(['src/translation/*'], gulp.series(['translation']));
gulp.watch(['src/**/*.html'], gulp.series(['html']));
gulp.watch(['src/views/*.html'], gulp.series(['html-views']));
gulp.watch(['src/templates/*.html'], gulp.series(['html-templates']));
gulp.watch(['scripts/createTimezones.js', 'src/js/utils.js'], gulp.series(['timezones']));
gulp.watch(['src/js/setup.js', 'src/js/client.js', 'src/js/utils.js'], gulp.series(['js-setup']));
gulp.watch(['src/js/setupdns.js', 'src/js/client.js', 'src/js/utils.js'], gulp.series(['js-setupdns']));
gulp.watch(['src/js/restore.js', 'src/js/client.js', 'src/js/utils.js'], gulp.series(['js-restore']));
gulp.watch(['src/js/passwordreset.js', 'src/js/utils.js'], gulp.series(['js-passwordreset']));
gulp.watch(['src/js/setupaccount.js', 'src/js/utils.js'], gulp.series(['js-setupaccount']));
gulp.watch(['src/js/index.js', 'src/js/client.js', 'src/views/*.js', 'src/js/utils.js'], gulp.series(['js-index']));
gulp.watch(['src/3rdparty/**/*'], gulp.series(['3rdparty']));
done();
});
gulp.task('serve', serve({ root: 'dist', port: 4000, hostname: '0.0.0.0' }));
gulp.task('develop', gulp.series(['default', 'watch', 'serve']));

211
dashboard/index.html Normal file
View File

@@ -0,0 +1,211 @@
<!DOCTYPE html>
<html ng-app="Application" ng-controller="MainController">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />
<!-- this gets changed once we get the config (because angular has not loaded yet, we see template string for a flash) -->
<title>Cloudron Dashboard</title>
<meta name="description" content="Cloudron Dashboard">
<link id="favicon" type="image/png" rel="icon" href="/api/v1/cloudron/avatar">
<link rel="apple-touch-icon" href="/api/v1/cloudron/avatar">
<link rel="icon" href="/api/v1/cloudron/avatar">
<!-- contains all thing already using import statement -->
<script type="module" src="./src/modules.js"></script>
<!-- jQuery-->
<script type="text/javascript" src="/js/jquery.min.js"></script>
<!-- CSS -->
<link type="text/css" rel="stylesheet" href="/slick.css"/>
<link type="text/css" rel="stylesheet" href="/angular-ui-notification.css"/>
<link type="text/css" rel="stylesheet" href="./src/theme.scss">
<!-- async -->
<script type="text/javascript" src="/js/async-3.2.0.min.js"></script>
<!-- Slick carousel -->
<script type="text/javascript" src="/js/slick.js"></script>
<!-- Angularjs scripts -->
<script type="text/javascript" src="/js/angular.min.js"></script>
<script type="text/javascript" src="/js/angular-loader.min.js"></script>
<script type="text/javascript" src="/js/angular-route.min.js"></script>
<script type="text/javascript" src="/js/angular-cookies.min.js"></script>
<script type="text/javascript" src="/js/angular-animate.min.js"></script>
<script type="text/javascript" src="/js/angular-base64.min.js"></script>
<script type="text/javascript" src="/js/angular-md5.min.js"></script>
<script type="text/javascript" src="/js/angular-sanitize.min.js"></script>
<script type="text/javascript" src="/js/angular-slick.min.js"></script>
<script type="text/javascript" src="/js/angular-ui-notification.js"></script>
<script type="text/javascript" src="/js/angular-fittext.min.js"></script>
<!-- Angular directives for bootstrap https://angular-ui.github.io/bootstrap/ -->
<script type="text/javascript" src="/js/ui-bootstrap-tpls-1.3.3.min.js"></script>
<!-- Angular translate https://angular-translate.github.io/ -->
<script type="text/javascript" src="/js/angular-translate.min.js"></script>
<script type="text/javascript" src="/js/angular-translate-loader-static-files.min.js"></script>
<script type="text/javascript" src="/js/angular-translate-storage-cookie.min.js"></script>
<script type="text/javascript" src="/js/angular-translate-storage-local.min.js"></script>
<script type="text/javascript" src="/js/clipboard.min.js"></script>
<!-- Showdown (markdown converter) -->
<script type="text/javascript" src="/js/showdown-1.9.1.min.js"></script>
<!-- Anugular Multiselect https://github.com/sebastianha/angular-bootstrap-multiselect -->
<script type="text/javascript" src="/js/angular-bootstrap-multiselect.js"></script>
<!-- timezone list -->
<script type="text/javascript" src="/js/timezones.js?%VITE_CACHE_ID%"></script>
<!-- Main Application -->
<!-- for now we need this in a static non transformed index.js file -->
<script> window.VITE_CACHE_ID = '%VITE_CACHE_ID%' </script>
<script type="text/javascript" src="/js/index.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/js/client.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/js/utils.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/app.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/apps.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/appstore.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/backups.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/branding.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/domains.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/email.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/emails-eventlog.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/emails.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/emails-queue.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/eventlog.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/network.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/notifications.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/profile.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/services.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/settings.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/support.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/system.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/user-directory.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/users.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/views/volumes.js?%VITE_CACHE_ID%"></script>
</head>
<body>
<script type="text/ng-template" id="notification.html">
<div class="ui-notification">
<h3 ng-show="title" ng-bind-html="title"></h3>
<div class="message">
<a href="{{action}}" ng-show="action" ng-bind-html="message"></a>
<span ng-hide="action" ng-bind-html="message"></span>
</div>
</div>
</script>
<a class="offline-banner animateMe" ng-show="client.offline" ng-cloak href="https://docs.cloudron.io/troubleshooting/" target="_blank"><i class="fa fa-circle-notch fa-spin"></i> {{ 'main.offline' | tr }}</a>
<!-- Modal reboot server -->
<div class="modal fade" id="rebootModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">{{ 'main.rebootDialog.title' | tr }}</h4>
</div>
<div class="modal-body">
<p class="text-bold">{{ 'main.rebootDialog.warning' | tr }}</p>
<p>{{ 'main.rebootDialog.description' | tr }}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'main.dialog.cancel' | tr }}</button>
<button type="button" class="btn btn-danger" ng-click="reboot.submit()" ng-disabled="reboot.busy"><i class="fa fa-circle-notch fa-spin" ng-show="reboot.busy"></i> {{ 'main.rebootDialog.rebootAction' | tr }}</button>
</div>
</div>
</div>
</div>
<div id="mainContentContainer" class="animateMe ng-hide layout-root" ng-show="initialized">
<!-- Navigation -->
<nav class="navbar navbar-default navbar-static-top shadow" role="navigation" style="margin-bottom: 0">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand navbar-brand-icon" href="#/"><img ng-src="{{ client.avatar }}" width="40" height="40"/></a>
<a class="navbar-brand" href="#/">{{ config.cloudronName || 'Cloudron' }}</a>
</div>
<!-- /.navbar-header -->
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav navbar-right" ng-hide="hideNavBarActions">
<li ng-show="user.isAtLeastOwner && (subscription.plan.id === 'free' || subscription.plan.id === 'expired')">
<a ng-click="openSubscriptionSetup()" style="cursor: pointer">
<span class="badge" ng-class="{'badge-danger': subscription.plan.id !== 'free', 'badge-success': subscription.plan.id === 'free' }">
{{ subscription.plan.id === 'free' ? ('settings.appstoreAccount.subscriptionSetupAction' | tr) : ('settings.appstoreAccount.subscriptionReactivateAction' | tr) }}
</span>
</a>
</li>
<li ng-show="!user.isAtLeastOwner && subscription.plan.id === 'expired'">
<a>
<span class="badge badge-danger">Subscription Expired</span>
</a>
</li>
<li>
<a ng-class="{ active: isActive('/apps')}" href="#/apps" ng-click="closeNavbar()"><i class="fa fa-grip fa-fw"></i> {{ 'apps.title' | tr }}</a>
</li>
<li ng-show="user.isAtLeastAdmin">
<a ng-class="{ active: isActive('/appstore')}" href="#/appstore" ng-click="closeNavbar()"><i class="fa fa-cloud-download-alt fa-fw"></i> {{ 'appstore.title' | tr }}</a>
</li>
<li ng-show="user.isAtLeastUserManager">
<a ng-class="{ active: isActive('/users')}" href="#/users" ng-click="closeNavbar()"><i class="fa fa-users fa-fw"></i> {{ 'main.navbar.users' | tr }}</a>
</li>
<li ng-show="user.isAtLeastAdmin">
<a href="#/notifications" ng-click="closeNavbar()">
<i class="fas fa-bell" ng-show="notificationCount"></i>
<i class="far fa-bell" ng-hide="notificationCount"></i>
<span class="badge badge-danger" ng-show="notificationCount">{{ notificationCount === 100 ? '100+' : notificationCount }}</span>
</a>
</li>
<li class="dropdown">
<a href="" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><img ng-src="{{user.avatarUrl}}" style="width: 24px; height: 24px;"/> {{user.username}} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="#/profile" ng-click="closeNavbar()"><i class="fa fa-user fa-fw"></i> {{ 'profile.title' | tr }}</a></li>
<li ng-show="user.isAtLeastMailManager" class="divider"></li>
<li ng-show="user.isAtLeastAdmin"><a href="#/backups" ng-click="closeNavbar()"><i class="fa fa-archive fa-fw"></i> {{ 'backups.title' | tr }}</a></li>
<li ng-show="user.isAtLeastAdmin"><a href="#/branding" ng-click="closeNavbar()"><i class="fa fa-passport fa-fw"></i> {{ 'branding.title' | tr }}</a></li>
<li ng-show="user.isAtLeastAdmin"><a href="#/domains" ng-click="closeNavbar()"><i class="fa fa-globe fa-fw"></i> {{ 'domains.title' | tr }}</a></li>
<li ng-show="user.isAtLeastMailManager"><a href="#/email" ng-click="closeNavbar()"><i class="fa fa-envelope fa-fw"></i> {{ 'emails.title' | tr }}</a></li>
<li ng-show="user.isAtLeastAdmin"><a href="#/eventlog" ng-click="closeNavbar()"><i class="fa fa-list-alt fa-fw"></i> {{ 'eventlog.title' | tr }}</a></li>
<li ng-show="user.isAtLeastAdmin"><a href="#/network" ng-click="closeNavbar()"><i class="fas fa-network-wired fa-fw"></i> {{ 'network.title' | tr }}</a></li>
<li ng-show="user.isAtLeastAdmin"><a href="#/services" ng-click="closeNavbar()"><i class="fa fa-cogs fa-fw"></i> {{ 'services.title' | tr }}</a></li>
<li ng-show="user.isAtLeastAdmin"><a href="#/settings" ng-click="closeNavbar()"><i class="fa fa-wrench fa-fw"></i> {{ 'settings.title' | tr }}</a></li>
<li ng-show="user.isAtLeastAdmin"><a href="#/user-directory" ng-click="closeNavbar()"><i class="fa fa-users-gear fa-fw"></i> {{ 'users.title' | tr }}</a></li>
<li ng-show="user.isAtLeastAdmin"><a href="#/volumes" ng-click="closeNavbar()"><i class="fa fa-hdd fa-fw"></i> {{ 'volumes.title' | tr }}</a></li>
<li ng-show="user.isAtLeastAdmin" class="divider"></li>
<li ng-show="user.isAtLeastOwner"><a href="#/support" ng-click="closeNavbar()"><i class="fa fa-comment fa-fw"></i> {{ 'support.title' | tr }}</a></li>
<li ng-show="user.isAtLeastAdmin"><a href="#/system" ng-click="closeNavbar()"><i class="fa fa-chart-area fa-fw"></i> {{ 'system.title' | tr }}</a></li>
<li class="divider"></li>
<li><a href="" ng-click="logout($event)"><i class="fa fa-sign-out-alt fa-fw"></i> {{ 'main.logout' | tr }}</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div ng-view id="ng-view" class="layout-content"></div>
<footer class="text-center ng-cloak">
<span class="text-muted" ng-bind-html="config.footer | markdown2html"></span>
</footer>
</div>
</body>
</html>

View File

@@ -5,6 +5,13 @@
<link rel="icon" href="/api/v1/cloudron/avatar" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Logs</title>
<style>
@media (prefers-color-scheme: dark) {
body {
background-color: black;
}
}
</style>
</head>
<body>
<div id="app"></div>

View File

@@ -23,7 +23,7 @@
height: 100%;
width: 100%;
text-align: center;
font-family: "Roboto","Helvetica Neue",Helvetica,Arial,sans-serif;
font-family: "Noto Sans", Helvetica, Arial, sans-serif;
font-size: 13px;
line-height: 1.846;
}
@@ -51,9 +51,19 @@
<script type="text/javascript">
window.addEventListener('load', (event) => {
document.getElementById('message').innerHTML =
'You are seeing this page because the DNS record of <b>' + window.location.hostname + '</b> is set to this server\'s IP'
// https://stackoverflow.com/questions/37437890/check-if-url-has-domain-name-and-not-an-ip
const containsLetter = /[a-zA-z]/.test(window.location.hostname); // ignore technicality that IP can contain letters ! http://192.168.0x1.0x1 or http://0xc0.0xa8.1.1
const isIPv6 = location.hostname.startsWith('[') && location.hostname.endsWith(']');
let message;
if (!containsLetter || isIPv6) { // ipv4 or ipv6
message = 'You cannot view Cloudron dashboard by IP address. Instead, navigate to the domain you configured during setup i.e <b>https://my.domain.example</b> .'
+ '<br>If you do not remember your domain, SSH into your server and run <code>cloudron-support --owner-login</code> .'
} else { // hostname
message = 'You are seeing this page because the DNS record of <b>' + window.location.hostname + '</b> is set to this server\'s IP'
+ ' but Cloudron has no app configured for this domain.';
}
document.getElementById('message').innerHTML = message;
});
</script>
</head>

16786
dashboard/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,36 +1,33 @@
{
"name": "dashboard",
"version": "1.0.0",
"description": "[Cloudron](https://cloudron.io) is the best way to run apps on your server.",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"update-translations": "curl https://translate.cloudron.io/api/components/cloudron/dashboard/file/ -o lang.zip && unzip -jo lang.zip -d ./src/translation/ && rm lang.zip"
"update-translations": "curl https://translate.cloudron.io/api/components/cloudron/dashboard/file/ -o lang.zip && unzip -jo lang.zip -d ./public/translation/ && rm lang.zip",
"dev": "vite --strictPort --port 4000",
"build": "vite build"
},
"repository": {
"type": "git",
"url": "ssh://git@git.cloudron.io:6000/cloudron/dashboard.git"
},
"author": "",
"license": "SEE LICENSE IN LICENSE",
"type": "module",
"dependencies": {
"@fortawesome/fontawesome-free": "^6.4.0",
"@eslint/js": "^9.16.0",
"@fontsource/noto-sans": "^5.1.0",
"@fortawesome/fontawesome-free": "^6.7.1",
"@vitejs/plugin-vue": "^5.2.1",
"@xterm/addon-attach": "^0.11.0",
"@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.5.0",
"anser": "^2.3.0",
"bootstrap-sass": "^3.4.3",
"chart.js": "^4.3.0",
"gulp": "^4.0.2",
"gulp-autoprefixer": "^8.0.0",
"gulp-concat": "^2.6.1",
"gulp-cssnano": "^2.1.3",
"gulp-ejs": "^5.1.0",
"gulp-sass": "^5.1.0",
"gulp-serve": "^1.4.0",
"gulp-sourcemaps": "^3.0.0",
"moment": "^2.29.4",
"sass": "^1.63.3",
"yargs": "^17.7.2"
},
"eslintConfig": {
"env": {
"browser": true
}
"chart.js": "^4.4.7",
"eslint-plugin-vue": "^9.32.0",
"filesize": "^10.1.6",
"jquery": "^3.7.1",
"marked": "^15.0.3",
"moment": "^2.30.1",
"pankow": "^2.4.2",
"pankow-viewers": "^1.0.11",
"sass": "^1.82.0",
"vite": "^6.0.3",
"vue": "^3.5.13",
"vue-i18n": "^10.0.5",
"vue-router": "^4.5.0"
}
}

View File

@@ -1,53 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />
<meta http-equiv="Content-Security-Policy" content="default-src <%= apiOrigin %> 'unsafe-inline' 'unsafe-eval' 'self'; img-src <%= apiOrigin %> 'self'" />
<meta charset="utf-8" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height" />
<!-- this gets changed once we get the status (because angular has not loaded yet, we see template string for a flash) -->
<title>Cloudron Password Reset</title>
<meta name="description" content="Cloudron Password Reset">
<!-- this gets changed once we get the status (because angular has not loaded yet, we see template string for a flash) -->
<title>Cloudron Password Reset</title>
<meta name="description" content="Cloudron Password Reset">
<link id="favicon" href="<%= apiOrigin %>/api/v1/cloudron/avatar" rel="icon" type="image/png">
<link id="favicon" href="/api/v1/cloudron/avatar" rel="icon" type="image/png">
<!-- Theme CSS -->
<link type="text/css" rel="stylesheet" href="/theme.css?<%= revision %>">
<!-- contains all thing already using import statement -->
<script type="module" src="./src/modules.js"></script>
<!-- Fontawesome -->
<link type="text/css" rel="stylesheet" href="/3rdparty/fontawesome/css/all.css?<%= revision %>"/>
<!-- Theme CSS -->
<link type="text/css" rel="stylesheet" href="./src/theme.scss">
<!-- jQuery-->
<script type="text/javascript" src="/3rdparty/js/jquery.min.js?<%= revision %>"></script>
<!-- jQuery-->
<script type="text/javascript" src="/js/jquery.min.js"></script>
<!-- async -->
<script type="text/javascript" src="/3rdparty/js/async-3.2.0.min.js?<%= revision %>"></script>
<!-- async -->
<script type="text/javascript" src="/js/async-3.2.0.min.js"></script>
<!-- Bootstrap Core JavaScript -->
<script type="text/javascript" src="/3rdparty/js/bootstrap.min.js?<%= revision %>"></script>
<!-- Showdown (markdown converter) -->
<script type="text/javascript" src="/js/showdown-1.9.1.min.js"></script>
<!-- Showdown (markdown converter) -->
<script type="text/javascript" src="/3rdparty/js/showdown-1.9.1.min.js?<%= revision %>"></script>
<!-- Angularjs scripts -->
<script type="text/javascript" src="/js/angular.min.js"></script>
<script type="text/javascript" src="/js/angular-loader.min.js"></script>
<script type="text/javascript" src="/js/angular-cookies.min.js"></script>
<!-- Angularjs scripts -->
<script type="text/javascript" src="/3rdparty/js/angular.min.js?<%= revision %>"></script>
<script type="text/javascript" src="/3rdparty/js/angular-loader.min.js?<%= revision %>"></script>
<!-- <script type="text/javascript" src="/3rdparty/js/angular-md5.min.js"></script> -->
<!-- <script type="text/javascript" src="/3rdparty/js/angular-ui-notification.js"></script> -->
<script type="text/javascript" src="/3rdparty/js/angular-cookies.min.js?<%= revision %>"></script>
<script type="text/javascript" src="/3rdparty/js/autofill-event.js?<%= revision %>"></script>
<!-- Angular directives for bootstrap https://angular-ui.github.io/bootstrap/ -->
<script type="text/javascript" src="/js/ui-bootstrap-tpls-1.3.3.min.js"></script>
<!-- Angular directives for bootstrap https://angular-ui.github.io/bootstrap/ -->
<script type="text/javascript" src="/3rdparty/js/ui-bootstrap-tpls-1.3.3.min.js?<%= revision %>"></script>
<!-- Angular translate https://angular-translate.github.io/ -->
<script type="text/javascript" src="/js/angular-translate.min.js"></script>
<script type="text/javascript" src="/js/angular-translate-loader-static-files.min.js"></script>
<script type="text/javascript" src="/js/angular-translate-storage-cookie.min.js"></script>
<script type="text/javascript" src="/js/angular-translate-storage-local.min.js"></script>
<!-- Angular translate https://angular-translate.github.io/ -->
<script type="text/javascript" src="/3rdparty/js/angular-translate.min.js?<%= revision %>"></script>
<script type="text/javascript" src="/3rdparty/js/angular-translate-loader-static-files.min.js?<%= revision %>"></script>
<script type="text/javascript" src="/3rdparty/js/angular-translate-storage-cookie.min.js?<%= revision %>"></script>
<script type="text/javascript" src="/3rdparty/js/angular-translate-storage-local.min.js?<%= revision %>"></script>
<!-- Setup Application -->
<script type="text/javascript" src="/js/passwordreset.js?<%= revision %>"></script>
<!-- Setup Application -->
<script type="text/javascript" src="/js/passwordreset.js?%VITE_CACHE_ID%"></script>
<script type="text/javascript" src="/js/utils.js?%VITE_CACHE_ID%"></script>
</head>
@@ -59,7 +53,7 @@
<div class="card" style="padding: 20px; margin-top: 100px; max-width: 620px;">
<div class="row">
<div class="col-md-12" style="text-align: center;">
<img width="128" height="128" style="margin-top: -84px" src="<%= apiOrigin %>/api/v1/cloudron/avatar"/>
<img width="128" height="128" style="margin-top: -84px" src="/api/v1/cloudron/avatar"/>
<br/>
<h2>{{ 'passwordReset.title' | tr }}</h2>
</div>
@@ -87,7 +81,7 @@
<div class="card" style="padding: 20px; margin-top: 100px; max-width: 620px;">
<div class="row">
<div class="col-md-12" style="text-align: center;">
<img width="128" height="128" style="margin-top: -84px" src="<%= apiOrigin %>/api/v1/cloudron/avatar"/>
<img width="128" height="128" style="margin-top: -84px" src="/api/v1/cloudron/avatar"/>
<br/>
<h2 ng-hide="error">{{ 'passwordReset.emailSent.title' | tr }}</h2>
<h4 ng-show="error" class="has-error">{{ error }}</h4>
@@ -102,7 +96,7 @@
<div class="card" style="padding: 20px; margin-top: 100px; max-width: 620px;">
<div class="row">
<div class="col-md-12" style="text-align: center;">
<img width="128" height="128" style="margin-top: -84px" src="<%= apiOrigin %>/api/v1/cloudron/avatar"/>
<img width="128" height="128" style="margin-top: -84px" src="/api/v1/cloudron/avatar"/>
<br/>
<h2>{{ 'passwordReset.newPassword.title' | tr }}</h2>
</div>
@@ -150,7 +144,7 @@
<div class="card" style="padding: 20px; margin-top: 100px; max-width: 620px;">
<div class="row">
<div class="col-md-12" style="text-align: center;">
<img width="128" height="128" style="margin-top: -84px" src="<%= apiOrigin %>/api/v1/cloudron/avatar"/>
<img width="128" height="128" style="margin-top: -84px" src="/api/v1/cloudron/avatar"/>
<br/>
<h2>{{ 'passwordReset.success.title' | tr }}</h2>
<br/>

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,19 +1,19 @@
'use strict';
/* global angular */
/* global $ */
/* global $, angular, redirectIfNeeded */
// create main application module
var app = angular.module('Application', ['pascalprecht.translate', 'ngCookies', 'angular-md5', 'ui-notification', 'ui.bootstrap']);
app.controller('SetupController', ['$scope', 'Client', function ($scope, Client) {
// Stupid angular location provider either wants html5 location mode or not, do the query parsing on my own
var search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
const search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
$scope.client = Client;
$scope.view = '';
$scope.initialized = false;
$scope.setupToken = '';
$scope.firstTimeLoginUrl = '';
$scope.owner = {
error: null,
@@ -36,7 +36,7 @@ app.controller('SetupController', ['$scope', 'Client', function ($scope, Client)
setupToken: $scope.setupToken
};
Client.createAdmin(data, function (error) {
Client.createAdmin(data, function (error, autoLoginToken) {
if (error && error.statusCode === 400) {
$scope.owner.busy = false;
@@ -59,38 +59,16 @@ app.controller('SetupController', ['$scope', 'Client', function ($scope, Client)
return;
}
// set token to autologin on first oidc flow
localStorage.cloudronFirstTimeToken = autoLoginToken;
$scope.firstTimeLoginUrl = '/openid/auth?client_id=cid-webadmin&scope=openid email profile&response_type=code token&redirect_uri=' + window.location.origin + '/authcallback.html';
setView('finished');
});
}
};
function redirectIfNeeded(status) {
if ('develop' in search || localStorage.getItem('develop')) {
console.warn('Cloudron develop mode on. To disable run localStorage.removeItem(\'develop\')');
localStorage.setItem('develop', true);
return;
}
// if we are here from https://ip/setup.html ,go to https://admin/setup.html
if (status.adminFqdn && status.adminFqdn !== window.location.hostname) {
window.location.href = 'https://' + status.adminFqdn + '/setup.html';
return true;
}
// if we don't have a domain yet, first go to domain setup
if (!status.adminFqdn) {
window.location.href = '/setupdns.html';
return true;
}
if (status.activated) {
window.location.href = '/';
return true;
}
return false;
}
function setView(view) {
if (view === 'finished') {
$scope.view = 'finished';
@@ -103,7 +81,8 @@ app.controller('SetupController', ['$scope', 'Client', function ($scope, Client)
Client.getProvisionStatus(function (error, status) {
if (error) return Client.initError(error, init);
if (redirectIfNeeded(status)) return;
if (redirectIfNeeded(status, 'activation')) return; // redirected to some other view...
setView(search.view);
$scope.setupToken = search.setupToken;

View File

@@ -1,26 +1,23 @@
'use strict';
/* global $ */
/* global angular */
/* global EventSource */
/* global async */
/* global $, angular, async */
// keep in sync with box/src/notfications.js
const NOTIFICATION_TYPES = {
ALERT_CLOUDRON_INSTALLED: 'cloudronInstalled',
ALERT_CLOUDRON_UPDATED: 'cloudronUpdated',
ALERT_CLOUDRON_UPDATE_FAILED: 'cloudronUpdateFailed',
ALERT_CERTIFICATE_RENEWAL_FAILED: 'certificateRenewalFailed',
ALERT_BACKUP_CONFIG: 'backupConfig',
ALERT_DISK_SPACE: 'diskSpace',
ALERT_MAIL_STATUS: 'mailStatus',
ALERT_REBOOT: 'reboot',
ALERT_BOX_UPDATE: 'boxUpdate',
ALERT_UPDATE_UBUNTU: 'ubuntuUpdate',
ALERT_MANUAL_APP_UPDATE: 'manualAppUpdate',
ALERT_APP_OOM: 'appOutOfMemory',
ALERT_APP_UPDATED: 'appUpdated',
ALERT_BACKUP_FAILED: 'backupFailed',
CLOUDRON_INSTALLED: 'cloudronInstalled',
CLOUDRON_UPDATED: 'cloudronUpdated',
CLOUDRON_UPDATE_FAILED: 'cloudronUpdateFailed',
CERTIFICATE_RENEWAL_FAILED: 'certificateRenewalFailed',
BACKUP_CONFIG: 'backupConfig',
DISK_SPACE: 'diskSpace',
MAIL_STATUS: 'mailStatus',
REBOOT: 'reboot',
BOX_UPDATE: 'boxUpdate',
UPDATE_UBUNTU: 'ubuntuUpdate',
MANUAL_APP_UPDATE: 'manualAppUpdate',
APP_OOM: 'appOutOfMemory',
APP_UPDATED: 'appUpdated',
BACKUP_FAILED: 'backupFailed',
};
// keep in sync with box/src/apps.js
@@ -167,10 +164,17 @@ const REGIONS_WASABI = [
{ name: 'Virginia (US East 2)', value: 'https://s3.us-east-2.wasabisys.com' }
];
const REGIONS_HETZNER = [
{ name: 'Falkenstein (FSN1)', value: 'https://fsn1.your-objectstorage.com' },
{ name: 'Helsinki (HEL1)', value: 'https://hel1.your-objectstorage.com' },
{ name: 'Nuremberg (NBG1)', value: 'https://nbg1.your-objectstorage.com' }
];
// https://docs.digitalocean.com/products/platform/availability-matrix/
const REGIONS_DIGITALOCEAN = [
{ name: 'AMS3', value: 'https://ams3.digitaloceanspaces.com' },
{ name: 'FRA1', value: 'https://fra1.digitaloceanspaces.com' },
{ name: 'LON1', value: 'https://lon1.digitaloceanspaces.com' },
{ name: 'NYC3', value: 'https://nyc3.digitaloceanspaces.com' },
{ name: 'SFO2', value: 'https://sfo2.digitaloceanspaces.com' },
{ name: 'SFO3', value: 'https://sfo3.digitaloceanspaces.com' },
@@ -181,6 +185,7 @@ const REGIONS_DIGITALOCEAN = [
// https://www.exoscale.com/datacenters/
const REGIONS_EXOSCALE = [
{ name: 'Vienna (AT-VIE-1)', value: 'https://sos-at-vie-1.exo.io' },
{ name: 'Vienna (AT-VIE-2)', value: 'https://sos-at-vie-2.exo.io' },
{ name: 'Sofia (BG-SOF-1)', value: 'https://sos-bg-sof-1.exo.io' },
{ name: 'Zurich (CH-DK-2)', value: 'https://sos-ch-dk-2.exo.io' },
{ name: 'Geneva (CH-GVA-2)', value: 'https://sos-ch-gva-2.exo.io' },
@@ -218,13 +223,14 @@ const REGIONS_LINODE = [
// note: ovh also has a storage endpoint but that only supports path style access (https://docs.ovh.com/au/en/storage/object-storage/s3/location/)
const REGIONS_OVH = [
{ name: 'Beauharnois (BHS)', value: 'https://s3.bhs.cloud.ovh.net', region: 'bhs' }, // default
{ name: 'Frankfurt (DE)', value: 'https://s3.de.cloud.ovh.net', region: 'de' },
{ name: 'Gravelines (GRA)', value: 'https://s3.gra.cloud.ovh.net', region: 'gra' },
{ name: 'Strasbourg (SBG)', value: 'https://s3.sbg.cloud.ovh.net', region: 'sbg' },
{ name: 'London (UK)', value: 'https://s3.uk.cloud.ovh.net', region: 'uk' },
{ name: 'Sydney (SYD)', value: 'https://s3.syd.cloud.ovh.net', region: 'syd' },
{ name: 'Warsaw (WAW)', value: 'https://s3.waw.cloud.ovh.net', region: 'waw' },
{ name: 'Beauharnois (BHS)', value: 'https://s3.bhs.io.cloud.ovh.net', region: 'bhs' }, // default
{ name: 'Frankfurt (DE)', value: 'https://s3.de.io.cloud.ovh.net', region: 'de' },
{ name: 'Gravelines (GRA)', value: 'https://s3.gra.io.cloud.ovh.net', region: 'gra' },
{ name: 'Roubaix (RBX)', value: 'https://s3.rbx.io.cloud.ovh.net', region: 'rbx' },
{ name: 'Strasbourg (SBG)', value: 'https://s3.sbg.io.cloud.ovh.net', region: 'sbg' },
{ name: 'London (UK)', value: 'https://s3.uk.io.cloud.ovh.net', region: 'uk' },
{ name: 'Sydney (SYD)', value: 'https://s3.syd.io.cloud.ovh.net', region: 'syd' },
{ name: 'Warsaw (WAW)', value: 'https://s3.waw.io.cloud.ovh.net', region: 'waw' },
];
const ENDPOINTS_OVH = [
@@ -239,9 +245,10 @@ const ENDPOINTS_OVH = [
// https://docs.ionos.com/cloud/managed-services/s3-object-storage/endpoints
const REGIONS_IONOS = [
{ name: 'Frankfurt (DE)', value: 'https://s3-de-central.profitbricks.com', region: 's3-de-central' }, // default
{ name: 'Berlin (eu-central-2)', value: 'https://s3-eu-central-2.ionoscloud.com', region: 'eu-central-2' }, // default
{ name: 'Logrono (eu-south-2)', value: 'https://s3-eu-south-2.ionoscloud.com', region: 'eu-south-2' }, // default
{ name: 'Berlin (eu-central-3)', value: 'https://s3.eu-central-3.ionoscloud.com', region: 'de' }, // default. contract-owned
{ name: 'Frankfurt (DE)', value: 'https://s3.eu-central-1.ionoscloud.com', region: 'de' },
{ name: 'Berlin (eu-central-2)', value: 'https://s3-eu-central-2.ionoscloud.com', region: 'eu-central-2' },
{ name: 'Logrono (eu-south-2)', value: 'https://s3-eu-south-2.ionoscloud.com', region: 'eu-south-2' },
];
// this is not used anywhere because upcloud needs endpoint URL. we detect region from the URL (https://upcloud.com/data-centres)
@@ -288,6 +295,7 @@ const STORAGE_PROVIDERS = [
{ name: 'Filesystem', value: 'filesystem' },
{ name: 'Filesystem (Mountpoint)', value: 'mountpoint' }, // legacy
{ name: 'Google Cloud Storage', value: 'gcs' },
{ name: 'Hetzner Object Storage', value: 'hetzner-objectstorage' },
{ name: 'IDrive e2', value: 'idrive-e2' },
{ name: 'IONOS (Profitbricks)', value: 'ionos-objectstorage' },
{ name: 'Linode Object Storage', value: 'linode-objectstorage' },
@@ -327,7 +335,7 @@ function prettyBinarySize(size, fallback) {
// we can also use KB here (JEDEC)
var i = Math.floor(Math.log(size) / Math.log(1024));
return (size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['B', 'KiB', 'MiB', 'GiB', 'TiB'][i];
return (size / Math.pow(1024, i)).toFixed(3) * 1 + ' ' + ['B', 'KiB', 'MiB', 'GiB', 'TiB'][i];
}
// decimal units (SI) 1000 based
@@ -365,6 +373,8 @@ angular.module('Application').filter('trKeyFromPeriod', function () {
angular.module('Application').filter('prettyDate', function ($translate) {
// http://ejohn.org/files/pretty.js
return function prettyDate(utc) {
if (utc === null) return $translate.instant('main.prettyDate.never', {});
var date = new Date(utc), // this converts utc into browser timezone and not cloudron timezone!
diff = (((new Date()).getTime() - date.getTime()) / 1000) + 30, // add 30seconds for clock skew
day_diff = Math.floor(diff / 86400);
@@ -417,7 +427,7 @@ angular.module('Application').filter('markdown2html', function () {
angular.module('Application').config(['$translateProvider', function ($translateProvider) {
$translateProvider.useStaticFilesLoader({
prefix: 'translation/',
suffix: '.json?' + '<%= revision %>'
suffix: '.json'
});
$translateProvider.useLocalStorage();
$translateProvider.preferredLanguage('en');
@@ -448,6 +458,73 @@ function translateFilterFactory($parse, $translate) {
translateFilterFactory.displayName = 'translateFilterFactory';
angular.module('Application').filter('tr', translateFilterFactory);
// checks provision status and redirects to correct view
// {
// setup: { active, message, errorMessage }
// restore { active, message, errorMessage }
// activated
// adminFqn
// }
// returns true if redirected . currentView is one of dashboard/restore/setup/activation
function redirectIfNeeded(status, currentView) {
var search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
if ('develop' in search || localStorage.getItem('develop')) {
console.warn('Cloudron develop mode on. To disable run localStorage.removeItem(\'develop\')');
localStorage.setItem('develop', true);
return false;
}
if (status.activated) {
console.log('Already activated');
if (currentView === 'dashboard') {
// support local development with localhost check
if (window.location.hostname !== status.adminFqdn && window.location.hostname !== 'localhost' && !window.location.hostname.startsWith('192.')) {
// user is accessing by IP or by the old admin location (pre-migration)
window.location.href = '/setup.html' + window.location.search;
return true;
}
return false;
}
window.location.href = 'https://' + status.adminFqdn + '/';
return true;
}
if (status.setup.active) {
console.log('Setup is active');
if (currentView === 'setup') return false;
window.location.href = '/setup.html' + window.location.search;
return true;
}
if (status.restore.active) {
console.log('Restore is active');
if (currentView === 'restore') return;
window.location.href = '/restore.html' + window.location.search;
return true;
}
if (status.adminFqdn) {
console.log('adminFqdn is set');
// if we are here from https://ip/activation.html ,go to https://admin/activation.html
if (status.adminFqdn !== window.location.hostname) {
window.location.href = 'https://' + status.adminFqdn + '/activation.html' + (window.location.search);
return true;
}
if (currentView === 'activation') return false;
window.location.href = 'https://' + status.adminFqdn + '/activation.html' + (window.location.search);
return true;
}
if (currentView === 'dashboard') {
window.location.href = '/setup.html' + window.location.search;
return true;
}
// if we are here, proceed with current view
return false;
}
// ----------------------------------------------
// Cloudron REST API wrapper
@@ -543,21 +620,6 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
.error(defaultErrorHandler(callback));
}
function head(url, config, callback) {
if (arguments.length !== 3) {
console.error('HEAD', arguments);
throw('Wrong number of arguments');
}
config = config || {};
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + token;
return $http.head(client.apiOrigin + url, config)
.success(defaultSuccessHandler(callback))
.error(defaultErrorHandler(callback));
}
function post(url, data, config, callback) {
if (arguments.length !== 4) {
console.error('POST', arguments);
@@ -619,7 +681,8 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
source: null,
avatarUrl: null,
avatarType: null,
hasBackgroundImage: false
hasBackgroundImage: false,
notificationConfig: []
};
this._config = {
consoleServerOrigin: null,
@@ -635,8 +698,9 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
this._installedAppsById = {};
this._appTags = [];
// window.location fallback for websocket connections which do not have relative uris
this.apiOrigin = '<%= apiOrigin %>' || window.location.origin;
this.apiOrigin = window.cloudronApiOrigin || window.location.origin;
this.avatar = '';
this.background = '';
this._availableLanguages = ['en'];
this._appstoreAppCache = [];
@@ -660,7 +724,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
// this happens mostly if the box crashes
if (message === 'Empty message or object') {
message = 'Got empty response. Click to check the server logs.';
action = action || '/frontend/logs.html?id=box';
action = action || '/logs.html?id=box';
}
this.notify('Cloudron Error', message, true, 'error', action);
@@ -670,7 +734,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
Client.prototype.initError = function (error, initFunction) {
console.error('Application startup error', error);
$timeout(initFunction, 5000); // we will try to re-init the app
// $timeout(initFunction, 5000); // we will try to re-init the app
};
Client.prototype.clearNotifications = function () {
@@ -750,6 +814,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
this._userInfo.avatarUrl = userInfo.avatarUrl + '?ts=' + Date.now(); // we add the timestamp to avoid caching
this._userInfo.avatarType = userInfo.avatarType;
this._userInfo.hasBackgroundImage = userInfo.hasBackgroundImage;
this._userInfo.notificationConfig = userInfo.notificationConfig;
this._userInfo.isAtLeastOwner = [ ROLES.OWNER ].indexOf(userInfo.role) !== -1;
this._userInfo.isAtLeastAdmin = [ ROLES.OWNER, ROLES.ADMIN ].indexOf(userInfo.role) !== -1;
this._userInfo.isAtLeastMailManager = [ ROLES.OWNER, ROLES.ADMIN, ROLES.MAIL_MANAGER ].indexOf(userInfo.role) !== -1;
@@ -761,9 +826,9 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
angular.copy(config, this._config);
<% if (appstore.consoleOrigin) { -%>
this._config.consoleServerOrigin = '<%= appstore.consoleOrigin %>';
<% } -%>
// <% if (appstore.consoleOrigin) { -%>
// this._config.consoleServerOrigin = '<%= appstore.consoleOrigin %>';
// <% } -%>
this._configListener.forEach(function (callback) {
callback(that._config);
@@ -825,6 +890,31 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
});
};
Client.prototype.hasCloudronBackground = function (callback) {
get('/api/v1/branding/cloudron_background', null, function (error, data, status) {
if (error && error.statusCode !== 404) callback(error);
else if (error) callback(null, false);
else callback(null, status === 200);
});
};
Client.prototype.changeCloudronBackground = function (background, callback) {
var fd = new FormData();
if (background) fd.append('background', background);
var config = {
headers: { 'Content-Type': undefined },
transformRequest: angular.identity
};
post('/api/v1/branding/cloudron_background', fd, config, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
callback(null);
});
};
Client.prototype.changeCloudronAvatar = function (avatarFile, callback) {
var fd = new FormData();
fd.append('avatar', avatarFile);
@@ -853,22 +943,23 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
});
};
Client.prototype.installApp = function (id, manifest, title, config, callback) {
Client.prototype.installApp = function (id, manifest, config, callback) {
var data = {
appStoreId: id + '@' + manifest.version,
subdomain: config.subdomain,
domain: config.domain,
secondaryDomains: config.secondaryDomains,
portBindings: config.portBindings,
ports: config.ports,
accessRestriction: config.accessRestriction,
cert: config.cert,
key: config.key,
sso: config.sso,
overwriteDns: config.overwriteDns,
upstreamUri: config.upstreamUri
upstreamUri: config.upstreamUri,
backupId: config.backupId // when restoring from archive
};
post('/api/v1/apps/install', data, null, function (error, data, status) {
post('/api/v1/apps', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
@@ -881,7 +972,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
subdomain: config.subdomain,
domain: config.domain,
secondaryDomains: config.secondaryDomains,
portBindings: config.portBindings,
ports: config.ports,
backupId: config.backupId,
overwriteDns: !!config.overwriteDns
};
@@ -916,6 +1007,17 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
});
};
Client.prototype.archiveApp = function (appId, backupId, callback) {
var data = { backupId: backupId };
post('/api/v1/apps/' + appId + '/archive', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
callback(null);
});
};
Client.prototype.uninstallApp = function (appId, callback) {
var data = {};
@@ -954,6 +1056,15 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
});
};
Client.prototype.ackAppChecklistItem = function (appId, key, acknowledged, callback) {
put('/api/v1/apps/' + appId + '/checklist/' + key, { done: acknowledged }, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
callback(null);
});
};
Client.prototype.updateApp = function (id, manifest, options, callback) {
var data = {
appStoreId: manifest.id + '@' + manifest.version,
@@ -1039,7 +1150,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
const storageConfig = Object.assign({}, backupConfig);
delete storageConfig.limits;
post('/api/v1/backups/config/storage', backupConfig, null, function (error, data, status) {
post('/api/v1/backups/config/storage', storageConfig, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
@@ -1292,8 +1403,6 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
};
Client.prototype.getUpdateInfo = function (callback) {
if (!this._userInfo.isAtLeastAdmin) return callback(new Error('Not allowed'));
get('/api/v1/updater/updates', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
@@ -1392,6 +1501,41 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
});
};
Client.prototype.listArchives = function (callback) {
var config = {
params: {
page: 1,
per_page: 100
}
};
get('/api/v1/archives', config, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data.archives);
});
};
Client.prototype.deleteArchive = function (id, callback) {
del('/api/v1/archives/' + id, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 204) return callback(new ClientError(status, data));
callback(null);
});
};
Client.prototype.unarchiveApp = function (archiveId, data, callback) {
post('/api/v1/archives/' + archiveId + '/unarchive', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
callback(null, data);
});
};
Client.prototype.getBackups = function (callback) {
var page = 1;
var perPage = 100;
@@ -1485,16 +1629,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
});
};
Client.prototype.restore = function (backupConfig, remotePath, version, ipv4Config, skipDnsSetup, setupToken, callback) {
var data = {
backupConfig: backupConfig,
remotePath: remotePath,
version: version,
ipv4Config: ipv4Config,
skipDnsSetup: skipDnsSetup,
setupToken: setupToken
};
Client.prototype.restore = function (data, callback) {
post('/api/v1/provision/restore', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status));
@@ -1830,15 +1965,6 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
});
};
Client.prototype.getAppLimits = function (appId, callback) {
get('/api/v1/apps/' + appId + '/limits', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data.limits);
});
};
Client.prototype.getAppWithTask = function (appId, callback) {
var that = this;
@@ -1888,6 +2014,15 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
});
};
Client.prototype.detectIp = function (callback) {
post('/api/v1/provision/detect_ip', {}, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data);
});
};
Client.prototype.setup = function (data, callback) {
post('/api/v1/provision/setup', data, null, function (error, data, status) {
if (error) return callback(error);
@@ -1913,10 +2048,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
if (error) return callback(error);
if (status !== 201) return callback(new ClientError(status, result));
that.setToken(result.token);
that.setUserInfo({ username: data.username, email: data.email, admin: true, twoFactorAuthenticationEnabled: false, source: '', avatarUrl: null });
callback(null, result.activated);
callback(null, result.token);
});
};
@@ -2082,15 +2214,6 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
});
};
Client.prototype.disks = function (callback) {
get('/api/v1/system/disks', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data);
});
};
Client.prototype.diskUsage = function (callback) {
get('/api/v1/system/disk_usage', null, function (error, data, status) {
if (error) return callback(error);
@@ -2216,7 +2339,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
// amend properties to mimick full app
data.applinks.forEach(function (applink) {
applink.type = APP_TYPES.LINK;
applink.fqdn = new URL(applink.upstreamUri).hostname;
applink.fqdn = applink.upstreamUri;
applink.manifest = { addons: {}};
applink.installationState = ISTATES.INSTALLED;
applink.runState = RSTATES.RUNNING;
@@ -2241,7 +2364,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
Client.prototype.updateApplink = function (id, data, callback) {
post('/api/v1/applinks/' + id, data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
if (status !== 200) return callback(new ClientError(status, data));
callback(null);
});
@@ -2336,6 +2459,15 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
});
};
Client.prototype.setNotificationConfig = function (notificationConfig, callback) {
post('/api/v1/profile/notification_config', { notificationConfig }, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 204) return callback(new ClientError(status, data));
callback(null, data);
});
};
Client.prototype.setProfileEmail = function (email, password, callback) {
post('/api/v1/profile/email', { email: email, password: password }, null, function (error, data, status) {
if (error) return callback(error);
@@ -2557,9 +2689,10 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
this.config(function (error, result) {
if (error) return callback(error);
that.getUpdateInfo(function (error, info) { // note: non-admin users may get access denied for this
if (!error) result.update = info.update; // attach update information to config object
that.getUpdateInfo(function (error, info) {
if (error) return callback(error);
result.update = info.update;
that.setConfig(result);
callback(null);
});
@@ -2727,8 +2860,10 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
Client.prototype.login = function () {
this.setToken(null);
localStorage.setItem('redirectToHash', window.location.hash);
// start oidc flow
window.location.href = this.apiOrigin + '/openid/auth?client_id=' + ('<%= apiOrigin %>' ? TOKEN_TYPES.ID_DEVELOPMENT : TOKEN_TYPES.ID_WEBADMIN) + '&scope=openid email profile&response_type=code token&redirect_uri=' + window.location.origin + '/authcallback.html';
window.location.href = this.apiOrigin + '/openid/auth?client_id=' + (window.cloudronApiOrigin ? TOKEN_TYPES.ID_DEVELOPMENT : TOKEN_TYPES.ID_WEBADMIN) + '&scope=openid email profile&response_type=code token&redirect_uri=' + window.location.origin + '/authcallback.html';
};
Client.prototype.logout = function () {
@@ -3030,18 +3165,18 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
});
};
Client.prototype.getSolrConfig = function (callback) {
Client.prototype.getFtsConfig = function (callback) {
var config = {};
get('/api/v1/mailserver/solr_config', config, function (error, data, status) {
get('/api/v1/mailserver/fts_config', config, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data);
});
};
Client.prototype.setSolrConfig = function (enabled, callback) {
post('/api/v1/mailserver/solr_config', { enabled: enabled }, null, function (error, data, status) {
Client.prototype.setFtsConfig = function (state, callback) {
post('/api/v1/mailserver/fts_config', { enable: state }, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
@@ -3060,7 +3195,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
};
Client.prototype.setSpamAcl = function (acl, callback) {
post('/api/v1/mailserver/spam_acl', { whitelist: acl.whitelist, blacklist: acl.blacklist }, null, function (error, data, status) {
post('/api/v1/mailserver/spam_acl', { allowlist: acl.allowlist, blocklist: acl.blocklist }, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
@@ -3438,8 +3573,6 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
mountOptions: mountOptions
};
console.log('---update', data)
post('/api/v1/volumes/' + volumeId, data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 204) return callback(new ClientError(status, data));
@@ -3482,8 +3615,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
// basically the user has not setup appstore account yet
if (!subscription.plan) return window.location.href = '/#/appstore';
if (subscription.plan.id === 'free') window.open(this.getConfig().consoleServerOrigin + '/#/subscription_setup/' + subscription.cloudronId + '?email=' + subscription.emailEncoded, '_blank');
else window.open(this.getConfig().consoleServerOrigin + '/#/cloudron/' + subscription.cloudronId + '?email=' + subscription.emailEncoded, '_blank');
window.open(this.getConfig().consoleServerOrigin + '/#/cloudron/' + subscription.cloudronId + '?email=' + subscription.emailEncoded, '_blank');
};
Client.prototype.getAppstoreAppByIdAndVersion = function (appId, version, callback) {
@@ -3593,10 +3725,18 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
var ACTION_APP_STOP = 'app.stop';
var ACTION_APP_RESTART = 'app.restart';
var ACTION_ARCHIVES_ADD = 'archives.add';
var ACTION_ARCHIVES_DEL = 'archives.del';
var ACTION_BACKUP_FINISH = 'backup.finish';
var ACTION_BACKUP_START = 'backup.start';
var ACTION_BACKUP_CLEANUP_START = 'backup.cleanup.start';
var ACTION_BACKUP_CLEANUP_FINISH = 'backup.cleanup.finish';
var ACTION_BRANDING_AVATAR = 'branding.avatar';
var ACTION_BRANDING_NAME = 'branding.name';
var ACTION_BRANDING_FOOTER = 'branding.footer';
var ACTION_CERTIFICATE_NEW = 'certificate.new';
var ACTION_CERTIFICATE_RENEWAL = 'certificate.renew';
var ACTION_CERTIFICATE_CLEANUP = 'certificate.cleanup';
@@ -3611,6 +3751,11 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
var ACTION_EXTERNAL_LDAP_CONFIGURE = 'externalldap.configure';
var ACTION_GROUP_ADD = 'group.add';
var ACTION_GROUP_UPDATE = 'group.update';
var ACTION_GROUP_REMOVE = 'group.remove';
var ACTION_GROUP_MEMBERSHIP = 'group.membership';
var ACTION_INSTALL_FINISH = 'cloudron.install.finish';
var ACTION_START = 'cloudron.start';
@@ -3627,6 +3772,8 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
var ACTION_USER_UPDATE = 'user.update';
var ACTION_USER_TRANSFER = 'user.transfer';
var ACTION_USER_DIRECTORY_PROFILE_CONFIG_UPDATE = 'userdirectory.profileconfig.update';
var ACTION_MAIL_LOCATION = 'mail.location';
var ACTION_MAIL_ENABLED = 'mail.enabled';
var ACTION_MAIL_DISABLED = 'mail.disabled';
@@ -3658,6 +3805,11 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
return pre + (app.label || app.fqdn || app.subdomain) + ' (' + app.manifest.title + ') ';
}
function eventBy() {
if (eventLog.source && eventLog.source.username) return ' by ' + eventLog.source.username;
return '';
}
switch (eventLog.action) {
case ACTION_ACTIVATE:
return 'Cloudron was activated';
@@ -3672,24 +3824,22 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
if (!data.app) return '';
app = data.app;
var q = function (x) {
return '"' + x + '"';
};
if ('accessRestriction' in data) { // since it can be null
return 'Access restriction ' + appName('of', app) + ' was changed';
} else if ('operators' in data) {
return 'Operators ' + appName('of', app) + ' was changed';
} else if (data.label) {
return 'Label ' + appName('of', app) + ' was set to ' + q(data.label);
return `Label ${appName('of', app)} was set to ${data.label}`;
} else if (data.tags) {
return 'Tags ' + appName('of', app) + ' was set to ' + q(data.tags.join(','));
return `Tags ${appName('of', app)} was set to ${data.tags.join(', ')}`;
} else if (data.icon) {
return 'Icon ' + appName('of', app) + ' was changed';
} else if (data.memoryLimit) {
return 'Memory limit ' + appName('of', app) + ' was set to ' + data.memoryLimit;
} else if (data.cpuShares) {
return 'Memory limit ' + appName('of', app) + ' was set to ' + prettyBinarySize(data.memoryLimit);
} else if (data.cpuShares) { // replaced by cpuQuota in 8.0
return 'CPU shares ' + appName('of', app) + ' was set to ' + Math.round((data.cpuShares * 100)/1024) + '%';
} else if (data.cpuQuota) {
return 'CPU quota ' + appName('of', app) + ' was set to ' + data.cpuQuota + '%';
} else if (data.env) {
return 'Env vars ' + appName('of', app) + ' was changed';
} else if ('debugMode' in data) { // since it can be null
@@ -3699,9 +3849,9 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
return appName('', app, 'App') + ' was taken out of repair mode';
}
} else if ('enableBackup' in data) {
return 'Automatic backups ' + appName('of', app) + ' were ' + (data.enableBackup ? 'enabled' : 'disabled');
return 'Automatic backups ' + appName('of', app) + ' was ' + (data.enableBackup ? 'enabled' : 'disabled');
} else if ('enableAutomaticUpdate' in data) {
return 'Automatic updates ' + appName('of', app) + ' were ' + (data.enableAutomaticUpdate ? 'enabled' : 'disabled');
return 'Automatic updates ' + appName('of', app) + ' was ' + (data.enableAutomaticUpdate ? 'enabled' : 'disabled');
} else if ('reverseProxyConfig' in data) {
return 'Reverse proxy configuration ' + appName('of', app) + ' was updated';
} else if ('upstreamUri' in data) {
@@ -3736,11 +3886,11 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
} else {
return 'Icon ' + appName('of', app) + ' was reset';
}
} else if (('mailboxName' in data) && data.mailboxName !== data.app.mailboxName) {
} else if ('mailboxName' in data) {
if (data.mailboxName) {
return 'Mailbox ' + appName('of', app) + ' was set to ' + q(data.mailboxName);
return `Mailbox ${appName('of', app)} was set to ${data.mailboxDisplayName || '' } ${data.mailboxName}@${data.mailboxDomain}`;
} else {
return 'Mailbox ' + appName('of', app) + ' was reset';
return 'Mailbox ' + appName('of', app) + ' was disabled';
}
}
@@ -3749,7 +3899,7 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
case ACTION_APP_INSTALL:
if (!data.app) return '';
return data.app.manifest.title + ' (package v' + data.app.manifest.version + ') was installed ' + appName('at', data.app);
return data.app.manifest.title + ' (package v' + data.app.manifest.version + ') was installed ' + appName('at', data.app) + eventBy();
case ACTION_APP_RESTORE:
if (!data.app) return '';
@@ -3833,6 +3983,12 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
if (!data.app) return '';
return appName('', data.app, 'App') + ' was restarted';
case ACTION_ARCHIVES_ADD:
return 'Backup ' + data.backupId + ' added to archive';
case ACTION_ARCHIVES_DEL:
return 'Backup ' + data.backupId + ' deleted from archive';
case ACTION_BACKUP_START:
return 'Backup started';
@@ -3849,6 +4005,15 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
case ACTION_BACKUP_CLEANUP_FINISH:
return data.errorMessage ? 'Backup cleaner errored: ' + data.errorMessage : 'Backup cleaner removed ' + (data.removedBoxBackupPaths ? data.removedBoxBackupPaths.length : '0') + ' backups';
case ACTION_BRANDING_AVATAR:
return 'Cloudron Avatar Changed';
case ACTION_BRANDING_NAME:
return 'Cloudron Name set to ' + data.name;
case ACTION_BRANDING_FOOTER:
return 'Cloudron Footer set to ' + data.footer;
case ACTION_CERTIFICATE_NEW:
return 'Certificate install for ' + data.domain + (errorMessage ? ' failed' : ' succeeded');
@@ -3884,6 +4049,18 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
return 'External Directory set to ' + data.config.url + ' (' + data.config.provider + ')';
}
case ACTION_GROUP_ADD:
return 'Group ' + data.name + ' was added';
case ACTION_GROUP_UPDATE:
return 'Group name changed from ' + data.oldName + ' to ' + data.group.name;
case ACTION_GROUP_REMOVE:
return 'Group ' + data.group.name + ' was removed';
case ACTION_GROUP_MEMBERSHIP:
return 'Group membership of ' + data.group.name + ' changed. Now was ' + data.userIds.length + ' member(s).';
case ACTION_INSTALL_FINISH:
return 'Cloudron version ' + data.version + ' installed';
@@ -3955,9 +4132,11 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
case ACTION_USER_LOGIN:
if (data.mailboxId) {
return 'User ' + (data.user ? data.user.username : data.userId) + ' logged in to mailbox ' + data.mailboxId;
} else {
} else if (data.appId) {
app = this.getCachedAppSync(data.appId);
return 'User ' + (data.user ? data.user.username : data.userId) + ' logged in to ' + (app ? app.fqdn : data.appId);
} else { // can happen with directoryserver
return 'User ' + (data.user ? data.user.username : data.userId) + ' authenticated';
}
case ACTION_USER_LOGIN_GHOST:
@@ -3966,6 +4145,9 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
case ACTION_USER_LOGOUT:
return 'User ' + (data.user ? data.user.username : data.userId) + ' logged out';
case ACTION_USER_DIRECTORY_PROFILE_CONFIG_UPDATE:
return 'User directory profile config updated. Mandatory 2FA: ' + (data.config.mandatory2FA) + ' Lock profiles: ' + (data.config.lockUserProfiles);
case ACTION_DYNDNS_UPDATE: {
details = data.errorMessage ? 'Error updating DNS. ' : 'Updated DNS. ';
if (data.fromIpv4 !== data.toIpv4) details += 'From IPv4 ' + data.fromIpv4 + ' to ' + data.toIpv4 + '. ';
@@ -4001,8 +4183,6 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
if (source.appId) {
var app = this.getCachedAppSync(source.appId);
line += ' - ' + (app ? app.fqdn : source.appId);
} else if (source.ip) {
line += ' - ' + source.ip;
}
return line;

View File

@@ -1,8 +1,6 @@
'use strict';
/* global angular:false */
/* global $:false */
/* global async */
/* global $, async, angular, redirectIfNeeded */
/* global ERROR,ISTATES,HSTATES,RSTATES,APP_TYPES,NOTIFICATION_TYPES */
// deal with accessToken in the query, this is passed for example on password reset and account setup upon invite
@@ -19,7 +17,7 @@ if (search.accessToken) {
}
// create main application module
var app = angular.module('Application', ['pascalprecht.translate', 'ngCookies', 'ngFitText', 'ngRoute', 'ngAnimate', 'ngSanitize', 'angular-md5', 'base64', 'slick', 'ui-notification', 'ui.bootstrap', 'ui.bootstrap-slider', 'ngTld', 'ui.multiselect']);
var app = angular.module('Application', ['pascalprecht.translate', 'ngCookies', 'ngFitText', 'ngRoute', 'ngAnimate', 'ngSanitize', 'angular-md5', 'base64', 'slick', 'ui-notification', 'ui.bootstrap', 'ui.multiselect']);
app.config(['NotificationProvider', function (NotificationProvider) {
NotificationProvider.setOptions({
@@ -50,88 +48,88 @@ app.config(['$routeProvider', function ($routeProvider) {
redirectTo: '/apps'
}).when('/users', {
controller: 'UsersController',
templateUrl: 'views/users.html?<%= revision %>'
}).when('/usersettings', {
templateUrl: 'views/users.html?' + window.VITE_CACHE_ID
}).when('/user-directory', {
controller: 'UserSettingsController',
templateUrl: 'views/user-settings.html?<%= revision %>'
templateUrl: 'views/user-directory.html?' + window.VITE_CACHE_ID
}).when('/app/:appId/:view?', {
controller: 'AppController',
templateUrl: 'views/app.html?<%= revision %>'
templateUrl: 'views/app.html?' + window.VITE_CACHE_ID
}).when('/appstore', {
controller: 'AppStoreController',
templateUrl: 'views/appstore.html?<%= revision %>'
templateUrl: 'views/appstore.html?' + window.VITE_CACHE_ID
}).when('/appstore/:appId', {
controller: 'AppStoreController',
templateUrl: 'views/appstore.html?<%= revision %>'
templateUrl: 'views/appstore.html?' + window.VITE_CACHE_ID
}).when('/apps', {
controller: 'AppsController',
templateUrl: 'views/apps.html?<%= revision %>'
templateUrl: 'views/apps.html?' + window.VITE_CACHE_ID
}).when('/profile', {
controller: 'ProfileController',
templateUrl: 'views/profile.html?<%= revision %>'
templateUrl: 'views/profile.html?' + window.VITE_CACHE_ID
}).when('/backups', {
controller: 'BackupsController',
templateUrl: 'views/backups.html?<%= revision %>'
templateUrl: 'views/backups.html?' + window.VITE_CACHE_ID
}).when('/branding', {
controller: 'BrandingController',
templateUrl: 'views/branding.html?<%= revision %>'
templateUrl: 'views/branding.html?' + window.VITE_CACHE_ID
}).when('/network', {
controller: 'NetworkController',
templateUrl: 'views/network.html?<%= revision %>'
templateUrl: 'views/network.html?' + window.VITE_CACHE_ID
}).when('/domains', {
controller: 'DomainsController',
templateUrl: 'views/domains.html?<%= revision %>'
templateUrl: 'views/domains.html?' + window.VITE_CACHE_ID
}).when('/email', {
controller: 'EmailsController',
templateUrl: 'views/emails.html?<%= revision %>'
templateUrl: 'views/emails.html?' + window.VITE_CACHE_ID
}).when('/emails-eventlog', {
controller: 'EmailsEventlogController',
templateUrl: 'views/emails-eventlog.html?<%= revision %>'
templateUrl: 'views/emails-eventlog.html?' + window.VITE_CACHE_ID
}).when('/emails-queue', {
controller: 'EmailsQueueController',
templateUrl: 'views/emails-queue.html?<%= revision %>'
templateUrl: 'views/emails-queue.html?' + window.VITE_CACHE_ID
}).when('/email/:domain/:view?', {
controller: 'EmailController',
templateUrl: 'views/email.html?<%= revision %>'
templateUrl: 'views/email.html?' + window.VITE_CACHE_ID
}).when('/notifications', {
controller: 'NotificationsController',
templateUrl: 'views/notifications.html?<%= revision %>'
templateUrl: 'views/notifications.html?' + window.VITE_CACHE_ID
}).when('/oidc', {
redirectTo: '/usersettings'
redirectTo: '/user-directory'
}).when('/settings', {
controller: 'SettingsController',
templateUrl: 'views/settings.html?<%= revision %>'
templateUrl: 'views/settings.html?' + window.VITE_CACHE_ID
}).when('/eventlog', {
controller: 'EventLogController',
templateUrl: 'views/eventlog.html?<%= revision %>'
templateUrl: 'views/eventlog.html?' + window.VITE_CACHE_ID
}).when('/support', {
controller: 'SupportController',
templateUrl: 'views/support.html?<%= revision %>'
templateUrl: 'views/support.html?' + window.VITE_CACHE_ID
}).when('/system', {
controller: 'SystemController',
templateUrl: 'views/system.html?<%= revision %>'
templateUrl: 'views/system.html?' + window.VITE_CACHE_ID
}).when('/services', {
controller: 'ServicesController',
templateUrl: 'views/services.html?<%= revision %>'
templateUrl: 'views/services.html?' + window.VITE_CACHE_ID
}).when('/volumes', {
controller: 'VolumesController',
templateUrl: 'views/volumes.html?<%= revision %>'
templateUrl: 'views/volumes.html?' + window.VITE_CACHE_ID
}).otherwise({ redirectTo: '/'});
}]);
app.filter('notificationTypeToColor', function () {
return function (n) {
switch (n.type) {
case NOTIFICATION_TYPES.ALERT_REBOOT:
case NOTIFICATION_TYPES.ALERT_APP_OOM:
case NOTIFICATION_TYPES.ALERT_MAIL_STATUS:
case NOTIFICATION_TYPES.ALERT_CERTIFICATE_RENEWAL_FAILED:
case NOTIFICATION_TYPES.ALERT_DISK_SPACE:
case NOTIFICATION_TYPES.ALERT_BACKUP_CONFIG:
case NOTIFICATION_TYPES.ALERT_BACKUP_FAILED:
case NOTIFICATION_TYPES.REBOOT:
case NOTIFICATION_TYPES.APP_OOM:
case NOTIFICATION_TYPES.MAIL_STATUS:
case NOTIFICATION_TYPES.CERTIFICATE_RENEWAL_FAILED:
case NOTIFICATION_TYPES.DISK_SPACE:
case NOTIFICATION_TYPES.BACKUP_CONFIG:
case NOTIFICATION_TYPES.BACKUP_FAILED:
return '#ff4c4c';
case NOTIFICATION_TYPES.ALERT_BOX_UPDATE:
case NOTIFICATION_TYPES.ALERT_MANUAL_APP_UPDATE:
case NOTIFICATION_TYPES.BOX_UPDATE:
case NOTIFICATION_TYPES.MANUAL_APP_UPDATE:
return '#f0ad4e';
default:
return '#2196f3';
@@ -305,6 +303,36 @@ app.filter('installationActive', function () {
};
});
// color indicator in app list
app.filter('installationStateClass', function () {
const ERROR_CLASS = 'status-error';
const BUSY_CLASS = 'status-starting fa-beat-fade';
const INACTIVE_CLASS = 'status-inactive';
const ACTIVE_CLASS = 'status-active';
return function(app) {
if (!app) return '';
switch (app.installationState) {
case ISTATES.ERROR: return ERROR_CLASS;
case ISTATES.INSTALLED: {
if (app.debugMode) {
return INACTIVE_CLASS;
} else {
if (app.runState === RSTATES.RUNNING) {
if (!app.health) return BUSY_CLASS; // no data yet
if (app.type === APP_TYPES.LINK || app.health === HSTATES.HEALTHY) return ACTIVE_CLASS;
return ERROR_CLASS; // dead/exit/unhealthy
} else {
return INACTIVE_CLASS;
}
}
}
default: return BUSY_CLASS;
}
};
});
// this appears in the app grid
app.filter('installationStateLabel', function () {
return function(app) {
@@ -399,7 +427,7 @@ app.filter('errorSuggestion', function () {
};
});
app.filter('readyToUpdate', function () {
app.filter('canUpdate', function () {
return function (apps) {
return apps.every(function (app) {
return (app.installationState === ISTATES.ERROR) || (app.installationState === ISTATES.INSTALLED);
@@ -643,6 +671,10 @@ app.controller('MainController', ['$scope', '$route', '$timeout', '$location', '
$scope.hideNavBarActions = $location.path() === '/logs';
$scope.backgroundImageUrl = '';
$scope.closeNavbar = function () {
$('.navbar-collapse').collapse('hide');
};
$scope.reboot = {
busy: false,
@@ -706,7 +738,10 @@ app.controller('MainController', ['$scope', '$route', '$timeout', '$location', '
};
function redirectOnMandatory2FA() {
if (Client.getConfig().mandatory2FA && !Client.getUserInfo().twoFactorAuthenticationEnabled) {
if (Client.getConfig().mandatory2FA) {
if (Client.getUserInfo().twoFactorAuthenticationEnabled) return; // user already has 2fa
if (Client.getUserInfo().source && $scope.config.external2FA) return; // 2fa is external
$location.path('/profile').search({ setup2fa: true });
}
}
@@ -745,35 +780,12 @@ app.controller('MainController', ['$scope', '$route', '$timeout', '$location', '
});
}
function redirectIfNeeded(status) {
if (!status.activated) {
console.log('Not activated yet, redirecting', status);
if (status.restore.active || status.restore.errorMessage) { // show the error message in restore page
window.location.href = '/restore.html' + window.location.search;
} else if (status.adminFqdn) {
window.location.href = 'https://' + status.adminFqdn + '/setup.html' + (window.location.search);
} else {
window.location.href = '/setupdns.html' + window.location.search;
}
return true;
}
// support local development with localhost check
if (window.location.hostname !== status.adminFqdn && window.location.hostname !== 'localhost' && !window.location.hostname.startsWith('192.')) {
// user is accessing by IP or by the old admin location (pre-migration)
window.location.href = '/setupdns.html' + window.location.search;
return true;
}
return false;
}
// this loads the very first thing when accessing via IP or domain
function init() {
Client.getProvisionStatus(function (error, status) {
if (error) return Client.initError(error, init);
if (redirectIfNeeded(status)) return;
if (redirectIfNeeded(status, 'dashboard')) return; // we got redirected...
// check version and force reload if needed
if (!localStorage.version) {

File diff suppressed because one or more lines are too long

View File

@@ -59,7 +59,7 @@ app.filter('tr', translateFilterFactory);
app.controller('PasswordResetController', ['$scope', '$translate', '$http', function ($scope, $translate, $http) {
// Stupid angular location provider either wants html5 location mode or not, do the query parsing on my own
var search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.indexOf('=') === -1 ? [item, true] : [item.slice(0, item.indexOf('=')), item.slice(item.indexOf('=')+1)]; }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
const search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.indexOf('=') === -1 ? [item, true] : [item.slice(0, item.indexOf('=')), item.slice(item.indexOf('=')+1)]; }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
$scope.initialized = false;
$scope.mode = '';
@@ -72,7 +72,8 @@ app.controller('PasswordResetController', ['$scope', '$translate', '$http', func
$scope.passwordResetIdentifier = '';
$scope.newPassword = '';
$scope.newPasswordRepeat = '';
var API_ORIGIN = '<%= apiOrigin %>' || window.location.origin;
const API_ORIGIN = window.cloudronApiOrigin || window.location.origin;
$scope.onPasswordReset = function () {
$scope.busy = true;

View File

@@ -1,17 +1,11 @@
'use strict';
/* global $, angular, tld, SECRET_PLACEHOLDER, STORAGE_PROVIDERS, BACKUP_FORMATS */
/* global REGIONS_S3, REGIONS_WASABI, REGIONS_DIGITALOCEAN, REGIONS_EXOSCALE, REGIONS_SCALEWAY, REGIONS_LINODE, REGIONS_OVH, REGIONS_IONOS, REGIONS_UPCLOUD, REGIONS_VULTR, REGIONS_CONTABO */
/* global $, angular, SECRET_PLACEHOLDER, STORAGE_PROVIDERS, BACKUP_FORMATS, redirectIfNeeded */
/* global REGIONS_S3, REGIONS_WASABI, REGIONS_DIGITALOCEAN, REGIONS_EXOSCALE, REGIONS_SCALEWAY, REGIONS_LINODE, REGIONS_OVH, REGIONS_IONOS, REGIONS_UPCLOUD, REGIONS_VULTR, REGIONS_CONTABO, REGIONS_HETZNER */
// create main application module
var app = angular.module('Application', ['pascalprecht.translate', 'ngCookies', 'angular-md5', 'ui-notification', 'ui.bootstrap']);
app.filter('zoneName', function () {
return function (domain) {
return tld.getDomain(domain);
};
});
app.controller('RestoreController', ['$scope', 'Client', function ($scope, Client) {
var search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
@@ -51,7 +45,7 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
password: '',
diskPath: '',
user: '',
seal: false,
seal: true,
port: 22,
privateKey: ''
};
@@ -61,30 +55,29 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
$scope.mountOptions.diskPath = '/dev/disk/by-uuid/' + newValue.uuid;
});
$scope.sysinfo = {
$scope.ipv4Config = {
provider: 'generic',
ipv4: '',
ip: '',
ifname: ''
};
$scope.sysinfoProvider = [
$scope.ipv6Config = {
provider: 'generic',
ip: '',
ifname: ''
};
$scope.ipProviders = [
{ name: 'Disabled', value: 'noop' },
{ name: 'Public IP', value: 'generic' },
{ name: 'Static IP Address', value: 'fixed' },
{ name: 'Network Interface', value: 'network-interface' }
];
$scope.prettySysinfoProviderName = function (provider) {
switch (provider) {
case 'generic': return 'Public IP';
case 'fixed': return 'Static IP Address';
case 'network-interface': return 'Network Interface';
default: return 'Unknown';
}
};
$scope.s3Regions = REGIONS_S3;
$scope.wasabiRegions = REGIONS_WASABI;
$scope.doSpacesRegions = REGIONS_DIGITALOCEAN;
$scope.hetznerRegions = REGIONS_HETZNER;
$scope.exoscaleSosRegions = REGIONS_EXOSCALE;
$scope.scalewayRegions = REGIONS_SCALEWAY;
$scope.linodeRegions = REGIONS_LINODE;
@@ -100,7 +93,7 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
$scope.s3like = function (provider) {
return provider === 's3' || provider === 'minio' || provider === 's3-v4-compat' || provider === 'exoscale-sos'
|| provider === 'digitalocean-spaces' || provider === 'wasabi' || provider === 'scaleway-objectstorage'
|| provider === 'digitalocean-spaces' || provider === 'wasabi' || provider === 'scaleway-objectstorage' || provider === 'hetzner-objectstorage'
|| provider === 'linode-objectstorage' || provider === 'ovh-objectstorage' || provider === 'backblaze-b2' || provider === 'cloudflare-r2'
|| provider === 'ionos-objectstorage' || provider === 'vultr-objectstorage' || provider === 'upcloud-objectstorage' || provider === 'idrive-e2'
|| provider === 'contabo-objectstorage';
@@ -170,6 +163,9 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
backupConfig.signatureVersion = 'v4';
} else if (backupConfig.provider === 'digitalocean-spaces') {
backupConfig.region = 'us-east-1';
} else if (backupConfig.provider === 'hetzner-objectstorage') {
backupConfig.region = 'us-east-1';
backupConfig.signatureVersion = 'v4';
}
} else if (backupConfig.provider === 'gcs') {
backupConfig.bucket = $scope.bucket;
@@ -239,16 +235,17 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
return;
}
var sysinfoConfig = {
provider: $scope.sysinfo.provider
var data = {
backupConfig: backupConfig,
remotePath: $scope.remotePath.replace(/\.tar\.gz(\.enc)?$/, ''),
version: version ? version[1] : '',
ipv4Config: $scope.ipv4Config,
ipv6Config: $scope.ipv6Config,
skipDnsSetup: $scope.skipDnsSetup,
setupToken: $scope.setupToken
};
if ($scope.sysinfo.provider === 'fixed') {
sysinfoConfig.ip = $scope.sysinfo.ipv4;
} else if ($scope.sysinfo.provider === 'network-interface') {
sysinfoConfig.ifname = $scope.sysinfo.ifname;
}
Client.restore(backupConfig, $scope.remotePath.replace(/\.tar\.gz(\.enc)?$/, ''), version ? version[1] : '', sysinfoConfig, $scope.skipDnsSetup, $scope.setupToken, function (error) {
Client.restore(data, function (error) {
$scope.busy = false;
if (error) {
@@ -303,7 +300,7 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
$scope.busy = false;
$scope.error.generic = status.restore.errorMessage;
} else { // restore worked, redirect to admin page
window.location.href = '/';
window.location.href = 'https://' + status.adminFqdn + '/';
}
return;
}
@@ -362,14 +359,11 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
Client.getProvisionStatus(function (error, status) {
if (error) return Client.initError(error, init);
if (redirectIfNeeded(status, 'restore')) return; // redirected to some other view...
if (status.restore.active) return waitForRestore();
if (status.restore.errorMessage) $scope.error.generic = status.restore.errorMessage;
if (status.activated) {
window.location.href = '/';
return;
}
if (status.restore.errorMessage) $scope.error.generic = status.restore.errorMessage; // any previous restore error
Client.getProvisionBlockDevices(function (error, result) {
if (error) {
@@ -388,7 +382,13 @@ app.controller('RestoreController', ['$scope', 'Client', function ($scope, Clien
$scope.instanceId = search.instanceId;
$scope.setupToken = search.setupToken;
$scope.initialized = true;
Client.detectIp(function (error, ip) { // this is never supposed to error
if (!error) $scope.ipv4Config.provider = ip.ipv4 ? 'generic' : 'noop';
if (!error) $scope.ipv6Config.provider = ip.ipv6 ? 'generic' : 'noop';
$scope.initialized = true;
});
});
});
}

View File

@@ -1,16 +1,10 @@
'use strict';
/* global $, tld, angular, Clipboard, ENDPOINTS_OVH */
/* global $, angular, Clipboard, ENDPOINTS_OVH, redirectIfNeeded */
// create main application module
var app = angular.module('Application', ['pascalprecht.translate', 'ngCookies', 'angular-md5', 'ui-notification', 'ui.bootstrap']);
app.filter('zoneName', function () {
return function (domain) {
return tld.getDomain(domain);
};
});
app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', function ($scope, $http, $timeout, Client) {
var search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
@@ -19,12 +13,11 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
$scope.provider = '';
$scope.showDNSSetup = false;
$scope.instanceId = '';
$scope.isDomain = false;
$scope.isSubdomain = false;
$scope.advancedVisible = false;
$scope.clipboardDone = false;
$scope.search = window.location.search;
$scope.setupToken = '';
$scope.taskMinutesActive = null;
$scope.tlsProvider = [
{ name: 'Let\'s Encrypt Prod', value: 'letsencrypt-prod' },
@@ -34,27 +27,25 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
{ name: 'Self-Signed', value: 'fallback' }, // this is not 'Custom' because we don't allow user to upload certs during setup phase
];
$scope.sysinfo = {
$scope.ipv4Config = {
provider: 'generic',
ipv4: '',
ip: '',
ifname: ''
};
$scope.sysinfoProvider = [
$scope.ipv6Config = {
provider: 'generic',
ip: '',
ifname: ''
};
$scope.ipProviders = [
{ name: 'Disabled', value: 'noop' },
{ name: 'Public IP', value: 'generic' },
{ name: 'Static IP Address', value: 'fixed' },
{ name: 'Network Interface', value: 'network-interface' }
];
$scope.prettySysinfoProviderName = function (provider) {
switch (provider) {
case 'generic': return 'Public IP';
case 'fixed': return 'Static IP Address';
case 'network-interface': return 'Network Interface';
default: return 'Unknown';
}
};
$scope.ovhEndpoints = ENDPOINTS_OVH;
$scope.needsPort80 = function (dnsProvider, tlsProvider) {
@@ -65,30 +56,19 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
// If we migrate the api origin we have to poll the new location
if (search.admin_fqdn) Client.apiOrigin = 'https://' + search.admin_fqdn;
$scope.$watch('dnsCredentials.domain', function (newVal) {
if (!newVal) {
$scope.isDomain = false;
$scope.isSubdomain = false;
} else if (!tld.getDomain(newVal) || newVal[newVal.length-1] === '.') {
$scope.isDomain = false;
$scope.isSubdomain = false;
} else {
$scope.isDomain = true;
$scope.isSubdomain = tld.getDomain(newVal) !== newVal;
}
});
// keep in sync with domains.js
$scope.dnsProvider = [
{ name: 'AWS Route53', value: 'route53' },
{ name: 'Bunny', value: 'bunny' },
{ name: 'Cloudflare', value: 'cloudflare' },
{ name: 'deSEC', value: 'desec' },
{ name: 'DigitalOcean', value: 'digitalocean' },
{ name: 'DNSimple', value: 'dnsimple' },
{ name: 'Gandi LiveDNS', value: 'gandi' },
{ name: 'GoDaddy', value: 'godaddy' },
{ name: 'Google Cloud DNS', value: 'gcdns' },
{ name: 'Hetzner', value: 'hetzner' },
{ name: 'INWX', value: 'inwx' },
{ name: 'Linode', value: 'linode' },
{ name: 'Name.com', value: 'namecom' },
{ name: 'Namecheap', value: 'namecheap' },
@@ -108,6 +88,7 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
gcdnsKey: { keyFileName: '', content: '' },
digitalOceanToken: '',
gandiApiKey: '',
gandiTokenType: 'PAT',
cloudflareEmail: '',
cloudflareToken: '',
cloudflareTokenType: 'GlobalApiKey',
@@ -118,7 +99,10 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
bunnyAccessKey: '',
dnsimpleAccessToken: '',
hetznerToken: '',
inwxUsername: '',
inwxPassword: '',
vultrToken: '',
deSecToken: '',
nameComUsername: '',
nameComToken: '',
namecheapUsername: '',
@@ -201,6 +185,7 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
config.token = $scope.dnsCredentials.digitalOceanToken;
} else if (provider === 'gandi') {
config.token = $scope.dnsCredentials.gandiApiKey;
config.tokenType = $scope.dnsCredentials.gandiTokenType;
} else if (provider === 'godaddy') {
config.apiKey = $scope.dnsCredentials.godaddyApiKey;
config.apiSecret = $scope.dnsCredentials.godaddyApiSecret;
@@ -217,8 +202,13 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
config.accessToken = $scope.dnsCredentials.dnsimpleAccessToken;
} else if (provider === 'hetzner') {
config.token = $scope.dnsCredentials.hetznerToken;
} else if (provider === 'inwx') {
config.username = $scope.dnsCredentials.inwxUsername;
config.password = $scope.dnsCredentials.inwxPassword;
} else if (provider === 'vultr') {
config.token = $scope.dnsCredentials.vultrToken;
} else if (provider === 'desec') {
config.token = $scope.dnsCredentials.deSecToken;
} else if (provider === 'namecom') {
config.username = $scope.dnsCredentials.nameComUsername;
config.token = $scope.dnsCredentials.nameComToken;
@@ -248,15 +238,6 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
tlsConfig.wildcard = true;
}
var sysinfoConfig = {
provider: $scope.sysinfo.provider
};
if ($scope.sysinfo.provider === 'fixed') {
sysinfoConfig.ip = $scope.sysinfo.ipv4;
} else if ($scope.sysinfo.provider === 'network-interface') {
sysinfoConfig.ifname = $scope.sysinfo.ifname;
}
var data = {
domainConfig: {
domain: $scope.dnsCredentials.domain,
@@ -265,7 +246,8 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
config: config,
tlsConfig: tlsConfig
},
ipv4Config: sysinfoConfig,
ipv4Config: $scope.ipv4Config,
ipv6Config: $scope.ipv6Config,
providerToken: $scope.instanceId,
setupToken: $scope.setupToken
};
@@ -299,28 +281,30 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
$scope.state = 'initialized';
$scope.dnsCredentials.busy = false;
} else { // proceed to activation
window.location.href = 'https://' + status.adminFqdn + '/setup.html' + (window.location.search);
window.location.href = 'https://' + status.adminFqdn + '/activation.html' + (window.location.search);
}
return;
}
$scope.message = status.setup.message;
if (!error) {
$scope.message = status.setup.message;
$scope.taskMinutesActive = (new Date() - new Date(status.setup.startTime)) / 60000;
}
setTimeout(waitForDnsSetup, 5000);
});
}
function initialize() {
function init() {
Client.getProvisionStatus(function (error, status) {
if (error) {
// During domain migration, the box code restarts and can result in getStatus() failing temporarily
console.error(error);
$scope.state = 'waitingForBox';
return $timeout(initialize, 3000);
}
$scope.state = 'waitingForBox';
if (error) return Client.initError(error, init);
// domain is currently like a lock flag
if (status.adminFqdn) return waitForDnsSetup();
if (redirectIfNeeded(status, 'setup')) return; // redirected to some other view...
if (status.setup.active) return waitForDnsSetup();
$scope.error.setup = status.setup.errorMessage; // show any previous error
if (status.provider === 'digitalocean' || status.provider === 'digitalocean-mp') {
$scope.dnsCredentials.provider = 'digitalocean';
@@ -331,15 +315,22 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
} else if (status.provider === 'gce') {
$scope.dnsCredentials.provider = 'gcdns';
} else if (status.provider === 'ami') {
$scope.dnsCredentials.provider = 'route53';
// aws marketplace made a policy change that they one cannot provide route53 IAM credentials
$scope.dnsCredentials.provider = 'wildcard';
}
$scope.instanceId = search.instanceId;
$scope.setupToken = search.setupToken;
$scope.provider = status.provider;
$scope.state = 'initialized';
setTimeout(function () { $("[autofocus]:first").focus(); }, 100);
Client.detectIp(function (error, ip) { // this is never supposed to error
if (!error) $scope.ipv4Config.provider = ip.ipv4 ? 'generic' : 'noop';
if (!error) $scope.ipv6Config.provider = ip.ipv6 ? 'generic' : 'noop';
$scope.state = 'initialized';
setTimeout(function () { $("[autofocus]:first").focus(); }, 100);
});
});
}
@@ -349,5 +340,5 @@ app.controller('SetupDNSController', ['$scope', '$http', '$timeout', 'Client', f
$timeout(function () { $scope.clipboardDone = false; }, 5000);
});
initialize();
init();
}]);

View File

@@ -62,15 +62,16 @@ app.filter('tr', translateFilterFactory);
app.controller('SetupAccountController', ['$scope', '$translate', '$http', function ($scope, $translate, $http) {
// Stupid angular location provider either wants html5 location mode or not, do the query parsing on my own
var search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.indexOf('=') === -1 ? [item, true] : [item.slice(0, item.indexOf('=')), item.slice(item.indexOf('=')+1)]; }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
const search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.indexOf('=') === -1 ? [item, true] : [item.slice(0, item.indexOf('=')), item.slice(item.indexOf('=')+1)]; }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
var API_ORIGIN = '<%= apiOrigin %>' || window.location.origin;
const API_ORIGIN = window.cloudronApiOrigin || window.location.origin;
$scope.initialized = false;
$scope.busy = false;
$scope.error = null;
$scope.view = 'setup';
$scope.branding = null;
$scope.dashboardUrl = '';
$scope.profileLocked = !!search.profileLocked;
$scope.existingUsername = !!search.username;
@@ -122,8 +123,10 @@ app.controller('SetupAccountController', ['$scope', '$translate', '$http', funct
$http.post(API_ORIGIN + '/api/v1/auth/setup_account', data).success(function (data, status) {
if (status !== 201) return error(data, status);
// set token to autologin
localStorage.token = data.accessToken;
// set token to autologin on first oidc flow
localStorage.cloudronFirstTimeToken = data.accessToken;
$scope.dashboardUrl = '/openid/auth?client_id=cid-webadmin&scope=openid email profile&response_type=code token&redirect_uri=' + window.location.origin + '/authcallback.html';
$scope.view = 'done';
}).error(error);

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,7 @@
/* This file contains helpers which should not be part of client.js */
/* global angular */
angular.module('Application').directive('passwordReveal', function () {
var svgEye = '<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="eye" class="svg-inline--fa fa-eye fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M572.52 241.4C518.29 135.59 410.93 64 288 64S57.68 135.64 3.48 241.41a32.35 32.35 0 0 0 0 29.19C57.71 376.41 165.07 448 288 448s230.32-71.64 284.52-177.41a32.35 32.35 0 0 0 0-29.19zM288 400a144 144 0 1 1 144-144 143.93 143.93 0 0 1-144 144zm0-240a95.31 95.31 0 0 0-25.31 3.79 47.85 47.85 0 0 1-66.9 66.9A95.78 95.78 0 1 0 288 160z"></path></svg>';
var svgEyeSlash = '<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="eye-slash" class="svg-inline--fa fa-eye-slash fa-w-20" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M320 400c-75.85 0-137.25-58.71-142.9-133.11L72.2 185.82c-13.79 17.3-26.48 35.59-36.72 55.59a32.35 32.35 0 0 0 0 29.19C89.71 376.41 197.07 448 320 448c26.91 0 52.87-4 77.89-10.46L346 397.39a144.13 144.13 0 0 1-26 2.61zm313.82 58.1l-110.55-85.44a331.25 331.25 0 0 0 81.25-102.07 32.35 32.35 0 0 0 0-29.19C550.29 135.59 442.93 64 320 64a308.15 308.15 0 0 0-147.32 37.7L45.46 3.37A16 16 0 0 0 23 6.18L3.37 31.45A16 16 0 0 0 6.18 53.9l588.36 454.73a16 16 0 0 0 22.46-2.81l19.64-25.27a16 16 0 0 0-2.82-22.45zm-183.72-142l-39.3-30.38A94.75 94.75 0 0 0 416 256a94.76 94.76 0 0 0-121.31-92.21A47.65 47.65 0 0 1 304 192a46.64 46.64 0 0 1-1.54 10l-73.61-56.89A142.31 142.31 0 0 1 320 112a143.92 143.92 0 0 1 144 144c0 21.63-5.29 41.79-13.9 60.11z"></path></svg>';

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 192 KiB

After

Width:  |  Height:  |  Size: 192 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Some files were not shown because too many files have changed in this diff Show More