diff --git a/.circleci/config.yml b/.circleci/config.yml index 661a5c8..758474e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -53,6 +53,24 @@ jobs: command: | curl -s -L "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=$MAX_TOKEN&suffix=tar.gz" -o GeoLite2-Country.tar.gz tar -xzf GeoLite2-Country.tar.gz --strip-components 1 --wildcards "*.mmdb" + + - run: + name: Download and Extract ARM Nebula Binary + command: | + curl -LO https://github.com/slackhq/nebula/releases/download/v1.7.2/nebula-linux-arm64.tar.gz + tar -xzvf nebula-linux-arm64.tar.gz + + - run: + name: Rename ARM Nebula Binary + command: | + mv nebula nebula-arm + mv nebula-cert nebula-cert-arm + + - run: + name: Download and Extract Nebula Binary + command: | + curl -LO https://github.com/slackhq/nebula/releases/download/v1.7.2/nebula-linux-amd64.tar.gz + tar -xzvf nebula-linux-amd64.tar.gz - run: name: Build UI diff --git a/.gitignore b/.gitignore index 6f546b6..c627498 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,10 @@ todo.txt LICENCE tokens.json .vscode -GeoLite2-Country.mmdb \ No newline at end of file +GeoLite2-Country.mmdb +dns-blacklist.txt +zz_test_config +nebula-arm +nebula-arm-cert +nebula +nebula-cert \ No newline at end of file diff --git a/LICENCE b/LICENCE index 954fd0a..1cadf6a 100644 --- a/LICENCE +++ b/LICENCE @@ -1,31 +1,57 @@ -“Commons Clause” License Condition v1.0 - -The Software is provided to you by the Licensor under the -License, as defined below, subject to the following condition. - -Without limiting other conditions in the License, the grant -of rights under the License will not include, and the License -does not grant to you, the right to Sell the Software. - -For purposes of the foregoing, “Sell” means practicing any or -all of the rights granted to you under the License to provide -to third parties, for a fee or other consideration (including -without limitation fees for hosting or consulting/ support -services related to the Software), a product or service whose -value derives, entirely or substantially, from the functionality -of the Software. Any license notice or attribution required by -the License must also include this Commons Clause License -Condition notice. - Software: Cosmos-Server -License: Apache 2.0 with Commons Clause +License: Apache 2.0 with Commons Clause and Anti Tampering Clause Licensor: Yann Stepienik +--------------------------------------------------------------------- + + “Commons Clause” License Condition v1.0 + + The Software is provided to you by the Licensor under the + License, as defined below, subject to the following condition. + + Without limiting other conditions in the License, the grant + of rights under the License will not include, and the License + does not grant to you, the right to Sell the Software. + + For purposes of the foregoing, “Sell” means practicing any or + all of the rights granted to you under the License to provide + to third parties, for a fee or other consideration (including + without limitation fees for hosting or consulting/ support + services related to the Software), a product or service whose + value derives, entirely or substantially, from the functionality + of the Software. Any license notice or attribution required by + the License must also include this Commons Clause License + Condition notice. --------------------------------------------------------------------- + "Anti Tampering Clause” License Condition v1.0 + + Notwithstanding any provision of the Apache License 2.0, if the User + (or any party receiving or distributing derivative works, services, + or anything of value from the User related to the Software), directly + or indirectly, seeks to tamper with, alter, circumvent, or avoid + compliance with any subscription, paywall, feature restriction, or any + other licensing mechanism built into the Software or its usage, the + License granted under the Apache License 2.0 shall automatically and + immediately terminate, and access to the Software shall be withdrawn + with immediate effect. Upon such termination, any and all rights + established under the Apache License 2.0 shall be null and void. + + Tampering includes but is not limited to: (a) removing, disabling, + or circumventing any license key or other copy protection mechanism, + (b) redistributing parts or all of a feature that was intended + to be a paid feature, without keeping the restrictions, limitations, + or other licensing mechanisms with it(c) disabling, circumventing, or + avoiding any feature of the Software that is intended to enforce usage or + copy restrictions, or (d) providing or distributing any information + or code that enables disabling, circumvention, or avoidance of any + feature of the Software that is intended to enforce usage or copy + restrictions. + +--------------------------------------------------------------------- Apache License Version 2.0, January 2004 diff --git a/build.sh b/build.sh index bd48565..57b3348 100644 --- a/build.sh +++ b/build.sh @@ -18,6 +18,7 @@ echo " ---- Build complete, copy assets ----" cp -r static build/ cp -r GeoLite2-Country.mmdb build/ +cp nebula-arm-cert nebula-cert nebula-arm nebula build/ cp -r Logo.png build/ mkdir build/images cp client/src/assets/images/icons/cosmos_gray.png build/cosmos_gray.png diff --git a/changelog.md b/changelog.md index 4e3d8dc..3ad1a4d 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,19 @@ +<<<<<<< HEAD +## Version 0.9.20 - 0.9.21 + - Add option to disable CORS hardening (with empty value) + +======= +## Version 0.10.0 + - Added Constellation + - DNS Challenge is now used for all certificates when enabled [breaking change] + - Rework headers for better compatibility + - Improve experience for non-admin users + - Fix bug with redirect on logout + - Added OverwriteHostHeader to routes to override the host header sent to the target app + - Added WhitelistInboundIPs to routes to filter incoming requests based on IP per URL + + > **Note: If you use the ARM (:latest-arm) you need to manually update to using the :latest tag instead** + ## Version 0.9.20 - 0.9.21 - Add option to disable CORS hardening (with empty value) diff --git a/cla.md b/cla.md index 147f9d2..22a970d 100644 --- a/cla.md +++ b/cla.md @@ -2,7 +2,7 @@ Cosmos Software Grant and Contributor License Agreement (“Agreement”) This agreement is based on the Apache Software Foundation Contributor License Agreement. (v r190612) -Thank you for your interest in software projects stewarded by Raintank, Inc. dba Cosmos (“Cosmos”). In order to clarify the intellectual property license granted with Contributions from any person or entity, Cosmos must have a Contributor License Agreement (CLA) on file that has been agreed to by each Contributor, indicating agreement to the license terms below. This license is for your protection as a Contributor as well as the protection of Cosmos and its users; it does not change your rights to use your own Contributions for any other purpose. This Agreement allows an individual to contribute to Cosmos on that individual’s own behalf, or an entity (the “Corporation”) to submit Contributions to Cosmos, to authorize Contributions submitted by its designated employees to Cosmos, and to grant copyright and patent licenses thereto. +Thank you for your interest in dba Cosmos (“Cosmos”). In order to clarify the intellectual property license granted with Contributions from any person or entity, Cosmos must have a Contributor License Agreement (CLA) on file that has been agreed to by each Contributor, indicating agreement to the license terms below. This license is for your protection as a Contributor as well as the protection of Cosmos and its users; it does not change your rights to use your own Contributions for any other purpose. This Agreement allows an individual to contribute to Cosmos on that individual’s own behalf, or an entity (the “Corporation”) to submit Contributions to Cosmos, to authorize Contributions submitted by its designated employees to Cosmos, and to grant copyright and patent licenses thereto. You accept and agree to the following terms and conditions for Your present and future Contributions submitted to Cosmos. Except for the license granted herein to Cosmos and recipients of software distributed by Cosmos, You reserve all right, title, and interest in and to Your Contributions. diff --git a/client/src/api/constellation.demo.tsx b/client/src/api/constellation.demo.tsx new file mode 100644 index 0000000..1086548 --- /dev/null +++ b/client/src/api/constellation.demo.tsx @@ -0,0 +1,131 @@ +import wrap from './wrap'; + +function list() { + return new Promise((resolve, reject) => { + resolve({ + "data": [ + { + "nickname": "admin", + "deviceName": "phone", + "publicKey": "-----BEGIN NEBULA X25519 PRIVATE KEY-----\naACf/...=\n-----END NEBULA X25519 PRIVATE KEY-----\n", + "ip": "192.168.201.4/24", + "isLighthouse": false, + "isRelay": true, + "publicHostname": "", + "port": "4242", + "blocked": false, + "fingerprint": "..." + }, + { + "nickname": "admin", + "deviceName": "laptop", + "publicKey": "-----BEGIN NEBULA X25519 PRIVATE KEY-----\n78l4nDEB0+.../36YBQk7dkwg+.=\n-----END NEBULA X25519 PRIVATE KEY-----\n", + "ip": "192.168.201.5/24", + "isLighthouse": false, + "isRelay": true, + "publicHostname": "", + "port": "4242", + "blocked": false, + "fingerprint": "..." + }, + { + "nickname": "Martha", + "deviceName": "pink phone", + "publicKey": "-----BEGIN NEBULA X25519 PRIVATE KEY-----\naACf/..=\n-----END NEBULA X25519 PRIVATE KEY-----\n", + "ip": "192.168.201.6/24", + "isLighthouse": false, + "isRelay": true, + "publicHostname": "", + "port": "4242", + "blocked": false, + "fingerprint": "..." + } + ], + "status": "OK" + }) + }); +} + +function addDevice(device) { + return new Promise((resolve, reject) => { + resolve({ + "data": { + "CA": "-----BEGIN NEBULA CERTIFICATE-----\....\n+dfE+ikL8jUh/n+C+....\....\nZon/Dw==\n-----END NEBULA CERTIFICATE-----\n", + "Config": "constellation_api_key: ...\nconstellation_device_name: test\nconstellation_local_dns_overwrite: true\nconstellation_local_dns_overwrite_address: 192.168.201.1\nconstellation_public_hostname: \"\"\nfirewall:\n conntrack:\n default_timeout: 10m\n tcp_timeout: 12m\n udp_timeout: 3m\n inbound:\n - host: any\n port: any\n proto: any\n inbound_action: drop\n outbound:\n - host: any\n port: any\n proto: any\n outbound_action: drop\nlighthouse:\n am_lighthouse: false\n hosts:\n - 192.168.201.1\n interval: 60\nlisten:\n host: 0.0.0.0\n port: \"4242\"\nlogging:\n format: text\n level: info\npki:\n blocklist: []\n ca: |\n -----BEGIN NEBULA CERTIFICATE-----\n ...\n +dfE+ikL8jUh/n+C+...\n .\n Zon/Dw==\n -----END NEBULA CERTIFICATE-----\n cert: |\n -----BEGIN NEBULA CERTIFICATE-----\n CmIKBHRlc3QSCoeSo4UMgP7//..\n ...+QwZSiBxLdKhjkCH+.../..\n ./hfL+....\n ..==\n -----END NEBULA CERTIFICATE-----\n key: |\n -----BEGIN NEBULA X25519 PRIVATE KEY-----\n nS39dWX7uo1rhTvP2yl2XonGx3fWEkpk+43thNrMu7U=\n -----END NEBULA X25519 PRIVATE KEY-----\npunchy:\n punch: true\n respond: true\nrelay:\n am_relay: false\n relays:\n - 192.168.201.1\n use_relays: true\nstatic_host_map:\n 192.168.201.1:\n - vpn.domain.com:4242\ntun:\n dev: nebula1\n disabled: false\n drop_local_broadcast: false\n drop_multicast: false\n mtu: 1300\n routes: []\n tx_queue: 500\n unsafe_routes: []\n", + "DeviceName": "test", + "IP": "192.168.201.7/24", + "IsLighthouse": false, + "IsRelay": true, + "LighthousesList": [], + "Nickname": "admin", + "Port": "4242", + "PrivateKey": "-----BEGIN NEBULA CERTIFICATE-----\...//w8o3ZaFqQYwhdGFuAY6IGXmYRCr3z932Y....w\..==\n-----END NEBULA CERTIFICATE-----\n", + "PublicHostname": "", + "PublicKey": "-----BEGIN NEBULA X25519 PRIVATE KEY-----\nnS39dWX...hTvP......+43thNrMu7U=\n-----END NEBULA X25519 PRIVATE KEY-----\n" + }, + "status": "OK" + }) + }); +} + +function restart() { + return new Promise((resolve, reject) => { + resolve({ + "status": "ok", + }) + }); +} + + +function reset() { + return new Promise((resolve, reject) => { + resolve({ + "status": "ok", + }) + }); +} + +function getConfig() { + return new Promise((resolve, reject) => { + resolve({ + "data": "pki:\n ca: /config/ca.crt\n cert: /config/cosmos.crt\n key: /config/cosmos.key\n blocklist: []\nstatic_host_map:\n 192.168.201.1:\n - vpn.domain.com:4242\nlighthouse:\n am_lighthouse: true\n interval: 60\n hosts: []\nlisten:\n host: 0.0.0.0\n port: 4242\npunchy:\n punch: true\n respond: true\nrelay:\n am_relay: true\n use_relays: true\n relays: []\ntun:\n disabled: false\n dev: nebula1\n drop_local_broadcast: false\n drop_multicast: false\n tx_queue: 500\n mtu: 1300\n routes: []\n unsafe_routes: []\nlogging:\n level: info\n format: text\nfirewall:\n outbound_action: drop\n inbound_action: drop\n conntrack:\n tcp_timeout: 12m\n udp_timeout: 3m\n default_timeout: 10m\n outbound:\n - port: any\n proto: any\n host: any\n inbound:\n - port: any\n proto: any\n host: any\n", + "status": "OK" + }) + }); +} + +function getLogs() { + return new Promise((resolve, reject) => { + resolve({ + "data": "Some logs...", + "status": "OK" + }) + }); +} + +function connect(file) { + return new Promise((resolve, reject) => { + resolve({ + "status": "ok", + }) + }); +} + +function block(nickname, devicename, block) { + return new Promise((resolve, reject) => { + resolve({ + "status": "ok", + }) + }); +} + +export { + list, + addDevice, + restart, + getConfig, + getLogs, + reset, + connect, + block, +}; \ No newline at end of file diff --git a/client/src/api/constellation.tsx b/client/src/api/constellation.tsx new file mode 100644 index 0000000..36774c0 --- /dev/null +++ b/client/src/api/constellation.tsx @@ -0,0 +1,110 @@ +import wrap from './wrap'; + +function list() { + return wrap(fetch('/cosmos/api/constellation/devices', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + }, + })) +} + +function addDevice(device) { + return wrap(fetch('/cosmos/api/constellation/devices', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(device), + })) +} + +function restart() { + return wrap(fetch('/cosmos/api/constellation/restart', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + })) +} + + +function reset() { + return wrap(fetch('/cosmos/api/constellation/reset', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + })) +} + +function getConfig() { + return wrap(fetch('/cosmos/api/constellation/config', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + })) +} + +function getLogs() { + return wrap(fetch('/cosmos/api/constellation/logs', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + })) +} + +function connect(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.onload = () => { + fetch('/cosmos/api/constellation/connect', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', + }, + body: reader.result, + }) + .then(response => { + // Add additional response handling here if needed. + resolve(response); + }) + .catch(error => { + // Handle the error. + reject(error); + }); + }; + + reader.onerror = () => { + reject(new Error('Failed to read the file.')); + }; + + reader.readAsText(file); + }); +} + +function block(nickname, devicename, block) { + return wrap(fetch(`/cosmos/api/constellation/block`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + nickname, devicename, block + }), + })) +} + +export { + list, + addDevice, + restart, + getConfig, + getLogs, + reset, + connect, + block, +}; \ No newline at end of file diff --git a/client/src/api/demo.config.json b/client/src/api/demo.config.json index 470537e..a5d8fb2 100644 --- a/client/src/api/demo.config.json +++ b/client/src/api/demo.config.json @@ -361,7 +361,74 @@ ], "ServerCountry": "", "RequireMFA": false, - "AutoUpdate": false + "AutoUpdate": false, + "ConstellationConfig": { + "Enabled": true, + "SlaveMode": false, + "PrivateNode": false, + "DNSDisabled": false, + "DNSPort": "", + "DNSFallback": "8.8.8.8:53", + "DNSBlockBlacklist": true, + "DNSAdditionalBlocklists": [ + "https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt", + "https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt" + ], + "CustomDNSEntries": [], + "NebulaConfig": { + "PKI": { + "CA": "", + "Cert": "", + "Key": "", + "Blocklist": null + }, + "StaticHostMap": null, + "Lighthouse": { + "AMLighthouse": false, + "Interval": 0, + "Hosts": null + }, + "Listen": { + "Host": "", + "Port": 0 + }, + "Punchy": { + "Punch": false, + "Respond": false + }, + "Relay": { + "AMRelay": true, + "UseRelays": false, + "Relays": null + }, + "TUN": { + "Disabled": false, + "Dev": "", + "DropLocalBroadcast": false, + "DropMulticast": false, + "TxQueue": 0, + "MTU": 0, + "Routes": null, + "UnsafeRoutes": null + }, + "Logging": { + "Level": "", + "Format": "" + }, + "Firewall": { + "OutboundAction": "", + "InboundAction": "", + "Conntrack": { + "TCPTimeout": "", + "UDPTimeout": "", + "DefaultTimeout": "" + }, + "Outbound": null, + "Inbound": null + } + }, + "ConstellationHostname": "vpn.domain.com" + } }, "updates": { "/Sonarr": true, diff --git a/client/src/api/downloadButton.jsx b/client/src/api/downloadButton.jsx new file mode 100644 index 0000000..814e6a7 --- /dev/null +++ b/client/src/api/downloadButton.jsx @@ -0,0 +1,28 @@ +import { Button } from "@mui/material"; + +export const DownloadFile = ({ filename, content, label }) => { + const downloadFile = () => { + // Create a blob with the content + const blob = new Blob([content], { type: "text/plain;charset=utf-8" }); + + // Create a link element + const link = document.createElement("a"); + link.href = URL.createObjectURL(blob); + link.download = filename; + + // Append the link to the document (needed for Firefox) + document.body.appendChild(link); + + // Simulate a click to start the download + link.click(); + + // Cleanup the DOM by removing the link element + document.body.removeChild(link); + } + + return ( + + ); +} \ No newline at end of file diff --git a/client/src/api/index.jsx b/client/src/api/index.jsx index 492bc78..ab56be1 100644 --- a/client/src/api/index.jsx +++ b/client/src/api/index.jsx @@ -3,6 +3,7 @@ import * as _users from './users'; import * as _config from './config'; import * as _docker from './docker'; import * as _market from './market'; +import * as _constellation from './constellation'; import * as authDemo from './authentication.demo'; import * as usersDemo from './users.demo'; @@ -10,6 +11,7 @@ import * as configDemo from './config.demo'; import * as dockerDemo from './docker.demo'; import * as indexDemo from './index.demo'; import * as marketDemo from './market.demo'; +import * as constellationDemo from './constellation.demo'; import wrap from './wrap'; import { redirectToLocal } from '../utils/indexs'; @@ -211,6 +213,7 @@ let users = _users; let config = _config; let docker = _docker; let market = _market; +let constellation = _constellation; if(isDemo) { auth = authDemo; @@ -224,6 +227,7 @@ if(isDemo) { checkHost = indexDemo.checkHost; getDNS = indexDemo.getDNS; uploadBackground = indexDemo.uploadBackground; + constellation = constellationDemo; } export { @@ -232,6 +236,7 @@ export { config, docker, market, + constellation, getStatus, newInstall, isOnline, diff --git a/client/src/api/market.demo.ts b/client/src/api/market.demo.ts index 142c778..d3b86be 100644 --- a/client/src/api/market.demo.ts +++ b/client/src/api/market.demo.ts @@ -1,584 +1,9 @@ function list() { return new Promise((resolve, reject) => { - resolve({ - "data": { - "showcase": [ - { - "name": "Jellyfin", - "description": "Jellyfin is a Free Software Media System that puts you in control of managing and streaming your media. It is an alternative to the proprietary Plex, to provide media from a dedicated server to end-user devices via multiple apps.", - "url": "", - "longDescription": "

Jellyfin is an open-source media system that gives you the power to control the management and streaming of your media content. It offers an alternative to proprietary systems like Plex, empowering users to deliver media content from a dedicated server to various end-user devices through a range of apps.

Key features of Jellyfin include the ability to stream movies, TV shows, music, photos, videos, audiobooks, and podcasts. It also supports various technologies and platforms such as DLNA, Chromecast, Android, iOS, Roku, FireTV, SmartTV, Web browser, Kodi, and Emby. Jellyfin essentially functions as a comprehensive media browser, server, streaming system, player, center, manager, organizer, and library. In addition to these, it also facilitates media sharing, transcoding, and casting, offering a robust solution for your media needs.

", - "tags": [ - "media", - "server", - "streaming", - "movies", - "tv", - "music", - "photos", - "videos", - "audiobooks", - "podcasts", - "dlna", - "chromecast", - "android", - "ios", - "roku", - "firetv", - "smarttv", - "web", - "browser", - "kodi", - "emby", - "plex", - "media browser", - "media server", - "media streaming", - "media player", - "media center", - "media management", - "media organizer", - "media collection", - "media library", - "media manager", - "media sharing", - "media transcoding", - "media casting", - "media casting", - "media casting" - ], - "repository": "https://github.com/jellyfin/jellyfin", - "image": "https://hub.docker.com/r/linuxserver/jellyfin", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyfin/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyfin/screenshots/2.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyfin/screenshots/3.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyfin/screenshots/4.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyfin/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyfin/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Nextcloud", - "description": "Nextcloud is an open-source, self-hosted file share and collaboration platform, similar to Dropbox. It offers features such as file sharing, syncing, encryption, and collaboration tools. With its extensible app ecosystem, you can tailor your cloud storage service to your needs. Nextcloud is compatible with numerous platforms and can be integrated with many IT infrastructure systems.", - "url": "", - "longDescription": "

Nextcloud is a suite of client-server software for creating and using file hosting services. It is functionally similar to Dropbox, but is free and open-source, allowing users to install it on private servers.

Nextcloud provides an array of features including file sharing, syncing, end-to-end encryption, collaboration tools, and more. Its extensible app ecosystem allows you to set up your own cloud storage service to your exact needs. You can also integrate Nextcloud with many known IT infrastructure systems.

Available for Windows, Linux, MacOS, and other platforms, Nextcloud is designed to work in a variety of environments including both on premise and cloud setups. Start using Nextcloud today to control and secure your own private cloud storage!

", - "tags": [ - "storage", - "file sharing", - "syncing", - "encryption", - "collaboration", - "windows", - "linux", - "macos", - "self-hosted", - "nextcloud" - ], - "repository": "https://github.com/nextcloud/server", - "image": "https://hub.docker.com/r/linuxserver/nextcloud", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Nextcloud/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Nextcloud/screenshots/2.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Nextcloud/screenshots/3.jpg" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Nextcloud/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Nextcloud/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Plex", - "description": "Plex organizes all of your video, and music collections, and gives you instant access to them on all of your devices. With the free Plex Media Server software on your home computer and Plex for iOS, you can enjoy all of your personal media on your iPhone, iPad or iPod touch, and easily share it with friends and family. Plex also makes your media look beautiful with rich descriptions, artwork, and other related information. With an optional premium Plex Pass subscription, you can even sync videos, music, and photos to your smartphones and tablets to enjoy while offline. Parental controls, premium music features, music videos, trailers and extras, and powerful management tools are also part of our premium offering. Getting up and running is fast and simple, so get started now!", - "url": "", - "longDescription": "

Plex is a comprehensive media solution that organizes your video and music collections, giving you instant access across all your devices. With the free Plex Media Server software installed on your home computer and Plex's iOS app, you can enjoy your personal media on your iPhone, iPad, or iPod touch, and conveniently share it with your friends and family.

Plex is not just about easy access, it also enhances your media collection by adding rich descriptions, artwork, and other related information, making your media look visually appealing. If you choose to subscribe to the optional premium Plex Pass, you get the added ability to sync videos, music, and photos to your smartphones and tablets for offline enjoyment.

Premium features also include parental controls, enhanced music features, access to music videos, trailers, extras, and robust management tools. Starting with Plex is straightforward and quick. Get started today and transform your media experience!

", - "tags": [ - "media", - "movies", - "streaming", - "tv", - "music", - "photos", - "videos", - "audiobooks", - "podcasts", - "dlna", - "chromecast", - "android", - "ios", - "roku", - "firetv", - "smarttv", - "web", - "browser", - "kodi", - "emby", - "plex", - "media browser", - "media server", - "media streaming", - "media player", - "media center", - "media management", - "media organizer", - "media collection", - "media library", - "media manager", - "media sharing", - "media transcoding", - "media casting", - "media casting", - "media casting" - ], - "repository": "https://github.com/plex/plex", - "image": "https://hub.docker.com/r/linuxserver/plex", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Plex/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Plex/screenshots/2.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Plex/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Plex/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - } - ], - "all": { - "cosmos-cloud": [ - { - "name": "Bazarr", - "description": "Bazarr is an automated subtitle download application designed to complement Sonarr and Radarr. It simplifies the process of finding and downloading subtitles in various languages. Bazarr supports Windows, Linux, MacOS and provides a mobile-friendly web interface. If you're using Sonarr and Radarr, Bazarr can enhance your media management experience.", - "url": "", - "longDescription": "

Bazarr is a companion application to Sonarr and Radarr that manages and downloads subtitles based on your requirements. It was designed with the aim to make it easier for users to find and download subtitles for their media content.

Bazarr provides a simple and efficient interface to manage your subtitle collection, supporting many languages and integrating with popular subtitle providers. The software works seamlessly with Sonarr and Radarr to provide a unified experience for managing your media.

Bazarr supports a variety of platforms including Windows, Linux, and MacOS, and also offers a mobile-friendly web interface. Setting up Bazarr is easy, making it a must-have tool for anyone using Sonarr and Radarr.

", - "tags": [ - "download", - "subtitle", - "automation", - "downloader", - "media", - "collection", - "sonarr", - "radarr", - "windows", - "linux", - "macos", - "web interface", - "movie management", - "media management", - "bazarr" - ], - "repository": "https://github.com/morpheus65535/bazarr", - "image": "https://hub.docker.com/r/linuxserver/bazarr", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Bazarr/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Bazarr/screenshots/2.jpg" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Bazarr/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Bazarr/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Calibre", - "description": "Calibre is an open-source e-book management tool that allows users to organize, save, and manage e-books of various formats. It supports a wide range of e-book formats and offers features like format conversion, e-book syncing, news feeds from web sources, a built-in e-book viewer, and a server for online access.", - "url": "", - "longDescription": "

Calibre is a powerful, open-source e-book management tool. It allows users to organize, save and manage e-books of various formats. Calibre supports a wide range of e-book formats including EPUB, Kindle, PDF, and more.

With its easy-to-use interface, Calibre allows users to convert e-books from different formats, sync e-books with e-book readers, and even provides news feeds from web sources. Calibre also features a built-in e-book viewer and a server for online access to your book collection.

Calibre is available for a variety of platforms, including Windows, Linux, and MacOS.

", - "tags": [ - "e-book", - "library", - "reader", - "open-source", - "cross-platform", - "management", - "calibre", - "windows", - "linux", - "macos" - ], - "repository": "https://github.com/kovidgoyal/calibre", - "image": "https://hub.docker.com/r/linuxserver/calibre", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre/screenshots/2.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Calibre-web", - "description": "Calibre-web is a web application providing a clean interface for browsing, reading, and downloading eBooks using an existing Calibre database. It offers features like categorization, a browser-based eBook reader, sending eBooks to Kindle devices, user management, and Goodreads integration.", - "url": "", - "longDescription": "

Calibre-web is a web application providing a clean interface for browsing, reading and downloading eBooks using an existing Calibre database. This software is a fork of the original Calibre web with several additional features and enhancements.

Calibre-web allows users to sort and categorize eBooks, provides a browser-based eBook reader, and even allows the sending of eBooks to Kindle devices. It also supports user management to control access to the eBook collection and offers the ability to interface with Goodreads for book reviews and recommendations.

Calibre-web is compatible with Docker and can be used on any platform that supports Docker.

", - "tags": [ - "e-book", - "library", - "reader", - "web interface", - "management", - "calibre-web", - "docker", - "reading", - "goodreads", - "kindle" - ], - "repository": "https://github.com/janeczku/calibre-web", - "image": "https://hub.docker.com/r/linuxserver/calibre-web", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre-Web/screenshots/1.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre-Web/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre-Web/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Code-Server", - "description": "Code-Server is an open-source tool that enables running Visual Studio Code on a remote server. It provides a full VS Code experience, secure remote access, and compatibility with VS Code extensions. Code-Server is compatible with Windows, Linux, MacOS, and Docker.", - "url": "", - "longDescription": "

Code-Server is an open-source project that allows developers to run Visual Studio Code, a popular development environment, on any machine remotely. This makes it possible to code on your cloud server, which can be particularly beneficial when dealing with large datasets, complex computations, or restricted local resources.

Key features of Code-Server include full Visual Studio Code experience, secure access over SSH or HTTPS, and compatibility with VS Code extensions. It is also designed to be easy to install and get up and running.

Code-Server is available on various platforms including Windows, Linux, and MacOS, and it supports Docker, making it a highly versatile tool for developers across different environments.

", - "tags": [ - "development", - "visual studio code", - "code-server", - "open-source", - "cross-platform", - "VS Code", - "development environment", - "remote coding", - "SSH", - "HTTPS", - "windows", - "linux", - "macos", - "docker" - ], - "repository": "https://github.com/cdr/code-server", - "image": "https://hub.docker.com/r/codercom/code-server", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/CodeServer/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/CodeServer/screenshots/2.jpg" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/CodeServer/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/CodeServer/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Deluge", - "description": "Deluge is a lightweight, open-source BitTorrent client known for its extensibility and low resource demand. It supports multiple BitTorrent protocols, offers a web interface for remote control, and includes features like encryption, peer exchange, speed limits, and proxy support. Deluge is compatible with Windows, Linux, MacOS, and Docker.", - "url": "", - "longDescription": "

Deluge is a lightweight, open-source BitTorrent client. It's highly extendable via a rich collection of plugins and is noted for its multi-platform compatibility and low resource demand.

Key features include support for a wide range of BitTorrent protocols, a web interface for remote control, encryption, peer exchange, speed limits, and proxy support. With its intuitive interface, users can easily download and share files via the BitTorrent protocol.

Deluge is compatible with various platforms, including Windows, Linux, and MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", - "tags": [ - "download", - "torrent", - "bittorrent", - "cross-platform", - "BitTorrent client", - "file sharing", - "peer-to-peer", - "p2p", - "encryption", - "web interface", - "windows", - "linux", - "macos", - "docker" - ], - "repository": "https://github.com/deluge-torrent/deluge", - "image": "https://hub.docker.com/r/linuxserver/deluge", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Deluge/screenshots/1.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Deluge/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Deluge/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Docker Mailserver", - "description": "Docker Mailserver is a full-featured, open-source mailserver solution that runs on Docker. It supports various protocols such as SMTP, IMAP, POP3, and LDAP, and includes features such as spam protection, antivirus, DKIM signing, and automated SSL/TLS certificates. Docker Mailserver can be run on platforms that support Docker, including Linux, MacOS, and Windows.", - "url": "", - "longDescription": "

Docker Mailserver is a full-featured, open-source mailserver solution that is designed to run on Docker. It provides a comprehensive set of tools and features needed to run your own mailserver in a production environment.

Key features of Docker Mailserver include support for various protocols such as SMTP, IMAP, POP3, and LDAP. It also includes SpamAssassin for spam protection, ClamAV for antivirus, Postfix for SMTP, and Dovecot for IMAP/POP3. It also supports DKIM signing to authenticate your email and prevent phishing, and provides automated SSL/TLS certificates via Let's Encrypt.

Docker Mailserver is designed to be run on any platform that supports Docker, including Linux, MacOS, and Windows.

", - "tags": [ - "email", - "mail server", - "SMTP", - "docker mailserver", - "open-source", - "mail server", - "docker", - "IMAP", - "POP3", - "LDAP", - "spam protection", - "antivirus", - "DKIM", - "SSL/TLS", - "linux", - "macos", - "windows" - ], - "repository": "https://github.com/docker-mailserver/docker-mailserver", - "image": "https://hub.docker.com/r/mailserver/docker-mailserver", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/DockerMailServer/screenshots/1.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/DockerMailServer/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/DockerMailServer/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Duplicati", - "description": "Duplicati is an open-source backup software that creates, encrypts, and stores backups of your files. It offers AES-256 encryption, incremental backups, scheduling, automated backups, and backup verification. Duplicati is compatible with Windows, Linux, MacOS, and Docker.", - "url": "", - "longDescription": "

Duplicati is an open-source backup software designed to secure your data by creating, encrypting, and storing backups of your files. It can backup your files to local drives or various online storage services.

Key features of Duplicati include AES-256 encryption, incremental backups, scheduling, and automated backups. It also supports backup verification, ensuring that your files are not corrupted or lost. Its web-based interface makes it easy to manage and schedule your backups.

Duplicati is compatible with various platforms, including Windows, Linux, and MacOS, and it supports Docker, making it a versatile tool for various environments.

", - "tags": [ - "backup", - "automation", - "encryption", - "open-source", - "cross-platform", - "backup", - "encryption", - "scheduling", - "automated backup", - "windows", - "linux", - "macos", - "docker" - ], - "repository": "https://github.com/duplicati/duplicati", - "image": "https://hub.docker.com/r/duplicati/duplicati", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Duplicati/screenshots/1.jpg", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Duplicati/screenshots/2.jpg" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Duplicati/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Duplicati/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Emulator-JS", - "description": "Emulator-JS is an open-source, in-browser multi-system emulator. It allows users to play games from various console systems directly in the browser, facilitated by an intuitive ROM management system. Emulator-JS can be used on any platform that supports a modern web browser, such as Windows, Linux, MacOS, and mobile devices.", - "url": "", - "longDescription": "

Emulator-JS is an open-source, in-browser multi-system emulator. It leverages JavaScript to emulate a wide range of gaming consoles, creating a convenient, accessible, and platform-agnostic gaming experience.

Key features of Emulator-JS include compatibility with multiple console systems, an intuitive ROM management system, and the ability to save game states. Because it's browser-based, Emulator-JS eliminates the need for complex installations or system-specific emulators.

As Emulator-JS runs directly in the browser, it can be used on any platform that supports a modern web browser, including Windows, Linux, MacOS, and even mobile devices. This makes it highly versatile for users across different environments.

", - "tags": [ - "gaming", - "emulation", - "web", - "open-source", - "cross-platform", - "emulator", - "in-browser", - "gaming", - "rom management", - "javascript", - "windows", - "linux", - "macos", - "mobile" - ], - "repository": "https://github.com/EmulatorJS/EmulatorJS", - "image": "https://hub.docker.com/r/linuxserver/emulatorjs", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Emulator-JS/screenshots/1.jpg", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Emulator-JS/screenshots/2.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Emulator-JS/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Emulator-JS/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "FreshRSS", - "description": "FreshRSS is an open-source, self-hosted RSS feed aggregator that is lightweight and easy to use. Features include a responsive design, import/export OPML files, multiple themes, filters, categories, multi-user support, and extensibility with plugins. FreshRSS is compatible with Windows, Linux, MacOS, and Docker.", - "url": "", - "longDescription": "

FreshRSS is an open-source, self-hosted RSS feed aggregator. It is lightweight, easy to use, and packed with features. FreshRSS lets you collect, manage, and read your RSS feeds from your own server, offering a high degree of control and privacy.

Key features include a responsive design that works well on desktop and mobile devices, the ability to import/export OPML files, multiple themes, filters, categories, and multi-user support with the ability to manage user roles. Furthermore, it's extensible with plugins for additional functionalities.

FreshRSS is compatible with various platforms, including Windows, Linux, and MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", - "tags": [ - "RSS", - "feed aggregator", - "news", - "freshrss", - "open-source", - "self-hosted", - "responsive", - "OPML", - "multi-user", - "windows", - "linux", - "macos", - "docker" - ], - "repository": "https://github.com/FreshRSS/FreshRSS", - "image": "https://hub.docker.com/r/linuxserver/freshrss", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/FreshRSS/screenshots/1.jpg" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/FreshRSS/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/FreshRSS/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Gitea", - "description": "Gitea is a lightweight, open-source Git platform for self-hosted repository management, code collaboration, and issue tracking. It offers an intuitive interface, powerful access control, and integrations with popular development tools.", - "url": "", - "longDescription": "

Gitea is a lightweight, open-source Git platform that provides a self-hosted solution for managing repositories, collaborative code reviews, and issue tracking.

With Gitea, you can easily create and manage Git repositories, track changes, collaborate with team members, and streamline your software development workflow. It offers a simple and intuitive user interface, powerful access control, and a range of features such as code highlighting, pull requests, and issue management.

Gitea is written in Go and is designed to be lightweight, fast, and easy to deploy. It supports multiple authentication methods, including built-in user accounts, LDAP, and OAuth. Gitea also provides integrations with popular development tools and services.

Whether you're a small team or a large organization, Gitea provides a flexible and customizable platform for hosting your Git repositories and managing your software projects.

", - "tags": [ - "development", - "git", - "repository management", - "code collaboration", - "issue tracking", - "go", - "self-hosted", - "gitea" - ], - "repository": "https://github.com/go-gitea/gitea", - "image": "https://hub.docker.com/r/gitea/gitea", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Gitea/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Gitea/screenshots/2.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Gitea/screenshots/3.jpg" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Gitea/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Gitea/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Grav", - "description": "Grav is an open-source, self-hosted, flat-file content management system (CMS). It offers features like content filtering, multi-language support, flexible templating with Twig, and simple content creation with Markdown. Grav can be extended with plugins and themes. It can be run on Windows, Linux, MacOS, and Docker.", - "url": "", - "longDescription": "

Grav is an open-source, self-hosted, flat-file content management system (CMS). Unlike traditional CMS platforms, Grav does not use a database to store content, making it incredibly lightweight and easy to manage.

Key features of Grav include powerful content filtering, multi-language support, flexible templating with Twig, and simple content creation process with Markdown. Its extendibility with a rich ecosystem of plugins and themes, plus a strong focus on performance, makes Grav a versatile platform for creating all kinds of websites.

Grav is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", - "tags": [ - "web", - "blog", - "code", - "open-source", - "self-hosted", - "CMS", - "flat-file", - "content management", - "twig", - "markdown", - "windows", - "linux", - "macos", - "docker" - ], - "repository": "https://github.com/getgrav/grav", - "image": "https://hub.docker.com/r/getgrav/grav", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Grav/screenshots/1.jpg" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Grav/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Grav/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Grocy", - "description": "Grocy is a self-hosted, open-source grocery management solution offering features like stock management with a barcode scanner, recipe management, household chore management, and tracking of purchased items with expiration dates. Grocy is compatible with Windows, Linux, MacOS, and Docker.", - "url": "", - "longDescription": "

Grocy is a self-hosted, open-source grocery management solution designed to help users manage their groceries. It provides a suite of tools for managing shopping lists, recipes, inventory, and chores.

Key features include stock management with a barcode scanner, recipe management, household chore management, and tracking of purchased items with expiration dates. Grocy helps users to avoid waste by providing reminders about due dates of perishable items.

Grocy is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", - "tags": [ - "life", - "groceries", - "list", - "open-source", - "self-hosted", - "grocery", - "management", - "shopping list", - "inventory", - "recipes", - "chores", - "windows", - "linux", - "macos", - "docker" - ], - "repository": "https://github.com/grocy/grocy", - "image": "https://hub.docker.com/r/linuxserver/grocy", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Grocy/screenshots/1.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Grocy/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Grocy/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Heimdall", - "description": "Heimdall is an open-source, self-hosted dashboard software that provides a central hub for web-based applications and services. Features include a built-in application library, custom themes, multi-user support, and compatibility with desktop and mobile browsers. Heimdall is compatible with Windows, Linux, MacOS, and Docker.", - "url": "", - "longDescription": "

Heimdall is an open-source, self-hosted dashboard software that allows you to organize and access your web-based applications and services all in one place. It's designed to provide a central hub to simplify your web environment.

Key features of Heimdall include the ability to add applications via a built-in library or by creating custom application definitions, custom themes, and the capacity to run on a desktop or mobile browser. It supports multiple users and each user can have their own personalized set of applications.

Heimdall is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", - "tags": [ - "dashboard", - "home", - "icons", - "open-source", - "self-hosted", - "web-based applications", - "services", - "central hub", - "multi-user", - "windows", - "linux", - "macos", - "docker" - ], - "repository": "https://github.com/linuxserver/Heimdall", - "image": "https://hub.docker.com/r/linuxserver/heimdall", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Heimdall/screenshots/1.jpg", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Heimdall/screenshots/2.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Heimdall/screenshots/3.jpg" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Heimdall/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Heimdall/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, + resolve({ + "data": { + "showcase": [ { "name": "Home Assistant", "description": "Home Assistant is an open-source home automation platform that focuses on privacy and local control. It allows you to control all your devices from a single interface, integrating with a large number of devices and services. Home Assistant offers advanced automation capabilities, running perfectly on a Raspberry Pi or a local server. Start using Home Assistant today for a comprehensive home automation solution.", @@ -611,39 +36,6 @@ function list() { "arm64" ] }, - { - "name": "Immich", - "description": "Immich - High performance self-hosted photo and video backup solution", - "url": "", - "longDescription": "

Immich is an open-source personal photo management tool that makes use of the latest technologies to provide an easy and intuitive way to keep your photos organized. It provides a web-based platform to browse, organize, and share your personal photo collection.

With features like smart search, automated tagging, and geolocation, Immich makes it easy to find and group your photos. It supports various image formats and RAW files from high-quality cameras. Immich can also automatically generate thumbnails and convert RAW images.

Available for Windows, Linux, MacOS, and other platforms, Immich offers a private, self-hosted solution for your photo management needs. Start using Immich today to take control of your photo collection!

", - "tags": [ - "photo management", - "image organizer", - "smart search", - "automated tagging", - "geolocation", - "thumbnails", - "RAW images", - "self-hosted", - "windows", - "linux", - "macos", - "Immich" - ], - "repository": "https://github.com/Immich/Immich", - "image": "https://hub.docker.com/r/Immich/Immich", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Immich/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Immich/screenshots/2.webp", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Immich/screenshots/3.jpg" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Immich/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Immich/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, { "name": "Jellyfin", "description": "Jellyfin is a Free Software Media System that puts you in control of managing and streaming your media. It is an alternative to the proprietary Plex, to provide media from a dedicated server to end-user devices via multiple apps.", @@ -703,207 +95,6 @@ function list() { "arm64" ] }, - { - "name": "Joplin", - "description": "Joplin is a free, open-source note-taking and to-do application that supports markdown and end-to-end encryption. It offers capabilities such as tagging, searching, and modifying notes, and can sync with various cloud platforms. It features an extensible plugin system, allowing for tailored functionality. Joplin is compatible across multiple platforms including Windows, Linux, MacOS, iOS, and Android.", - "url": "", - "longDescription": "

Joplin is a free and open-source note-taking and to-do application, which can handle a large number of notes organised into notebooks. The notes are searchable, can be copied, tagged and modified directly from the applications or from your own text editor. It also supports markdown, with inline previewing.

Joplin offers end-to-end encryption and can synchronize with various cloud platforms, making it a secure choice for your note-taking needs. With its API, Joplin can be extended with plugins for custom functionality, further tailoring your note management experience.

Available for Windows, Linux, MacOS, iOS, and Android, Joplin is flexible to fit a variety of environments and workflows. Start using Joplin today to organize your thoughts and tasks in a secure and efficient manner!

", - "tags": [ - "productivity", - "note-taking", - "to-do", - "markdown", - "encryption", - "syncing", - "windows", - "linux", - "macos", - "ios", - "android", - "self-hosted", - "joplin" - ], - "repository": "https://github.com/laurent22/joplin", - "image": "https://hub.docker.com/r/joplin/server", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Joplin/screenshots/1.jpg", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Joplin/screenshots/2.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Joplin/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Joplin/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "KitchenOwl", - "description": "KitchenOwl helps you organize your grocery life.", - "url": "", - "longDescription": "

KitchenOwl is a smart grocery list and recipe manager.

Easily add items to your shopping list before you go shopping. You can also create recipes and get suggestions on what you want to cook.

Track your expenses so you know how much you've spent.

", - "tags": [ - "recipes", - "meals", - "shopping", - "planning", - "expenses", - "docker" - ], - "repository": "https://github.com/tombursch/kitchenowl", - "image": "https://hub.docker.com/r/tombursch/kitchenowl", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Kitchenowl/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Kitchenowl/screenshots/2.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Kitchenowl/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Kitchenowl/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Lemmy", - "description": "Lemmy is an open-source, self-hosted, federated link aggregator similar to Reddit. It offers community formation, moderation tools, content voting, and supports commenting and private messaging between users. Lemmy can be run on Windows, Linux, MacOS, and Docker.", - "url": "", - "longDescription": "

Lemmy is an open-source, self-hosted, federated link aggregator application similar to Reddit, which allows users to create their own communities and share links and posts with others.

Key features of Lemmy include its ability to form federated link-aggregator communities, moderation tools, and the ability to vote on content. It also supports commenting and private messaging between users. Lemmy is designed to consume minimal resources and can be easily self-hosted on small servers.

Lemmy is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", - "tags": [ - "social", - "federation", - "reddit", - "open-source", - "self-hosted", - "federated", - "link aggregator", - "community", - "moderation", - "content voting", - "windows", - "linux", - "macos", - "docker" - ], - "repository": "https://github.com/LemmyNet/lemmy", - "image": "https://hub.docker.com/r/dessalines/lemmy", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Lemmy/screenshots/1.jpg", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Lemmy/screenshots/2.webp" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Lemmy/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Lemmy/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Lidarr", - "description": "Lidarr is an automated music manager for maintaining your music library. It does this by finding and automatically downloading your desired music tracks. It integrates with popular download clients and supports metadata fetching from multiple music databases. With Lidarr, your music downloading and organization process can be streamlined and automated. It supports various platforms and has a mobile-friendly web interface for easy access. Get started with Lidarr now and enhance your music management experience!", - "url": "", - "longDescription": "

Lidarr is an automated music collection manager that can find, add, and manage music in your collection. With Lidarr, you can automatically search for new albums and singles from your favorite artists, and automatically download them to your media server. It is integrated with popular download clients and supports multiple music databases for metadata fetching.

Lidarr is a perfect solution for those who want to automate their music downloading and organization process. It is available for various platforms including Windows, Linux, and MacOS, and has a mobile-friendly web interface that works across different devices.

Setting up Lidarr is straightforward. Whether you are an audiophile with a large collection or someone who just loves listening to music, Lidarr can transform your music management experience!

", - "tags": [ - "download", - "torrent", - "music", - "usenet", - "automation", - "manager", - "media", - "collection", - "download", - "metadata", - "windows", - "linux", - "macos", - "web interface", - "streaming", - "music library", - "music database", - "music management", - "music collection", - "lidarr" - ], - "repository": "https://github.com/lidarr/Lidarr", - "image": "https://hub.docker.com/r/linuxserver/lidarr", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Lidarr/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Lidarr/screenshots/2.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Lidarr/screenshots/3.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Lidarr/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Lidarr/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Mastodon", - "description": "Mastodon is a free and open-source self-hosted social networking service. It features decentralization, ability to build your own community, per-post privacy settings, anti-abuse tools, and supports multimedia attachments. Mastodon can be run on any platform that supports Ruby, Node.js, and PostgreSQL, including various Linux distributions and Docker.", - "url": "", - "longDescription": "

Mastodon is a free and open-source self-hosted social networking service. It allows anyone to host their own server node in the network, while interacting with other users in a federated manner. It is similar to Twitter, but is distinguished by its decentralization and ability for users to host their own servers, and its character limit of 500 as opposed to Twitter's 280.

Key features of Mastodon include the ability to build your own community, granular, per-post privacy settings, and anti-abuse tools. It supports a rich variety of multimedia attachments in posts, and you can also choose to use content warnings on your posts for viewer discretion.

Mastodon can be run on any platform that supports Ruby, Node.js, and PostgreSQL, including various Linux distributions and Docker.

", - "tags": [ - "social", - "federation", - "reddit", - "open-source", - "self-hosted", - "federated", - "link aggregator", - "community", - "moderation", - "content voting", - "windows", - "linux", - "macos", - "docker" - ], - "repository": "https://github.com/tootsuite/mastodon", - "image": "https://hub.docker.com/r/tootsuite/mastodon", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Mastodon/screenshots/1.jpg", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Mastodon/screenshots/2.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Mastodon/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Mastodon/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "NZBGet", - "description": "NZBGet is a high-performance Usenet downloader that uses NZB files to fetch content. It is designed to use minimal system resources while offering features such as a web-interface, API, automatic post-processing, and RSS feed support. NZBGet works well on various platforms including low powered devices. Start using NZBGet for your Usenet downloads today!", - "url": "", - "longDescription": "

NZBGet is a robust and lightweight Usenet downloader. It can download files from Usenet servers via NZB index files. The software is focused on performance and uses very little system resources, while achieving high download speeds.

NZBGet offers a variety of features including web-interface, API, automatic post-processing, RSS feed support, and more. It is also designed to work well on low powered devices like Raspberry Pi.

Available on multiple platforms including Windows, MacOS, Linux, and others, NZBGet is easy to set up and use. Start using NZBGet today for efficient Usenet downloading!

", - "tags": [ - "download", - "torrent", - "usenet", - "downloader", - "nzb", - "windows", - "linux", - "macos", - "raspberry pi", - "performance", - "rss feed", - "post-processing", - "nzbget" - ], - "repository": "https://github.com/nzbget/nzbget", - "image": "https://hub.docker.com/r/linuxserver/nzbget", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/NZBGet/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/NZBGet/screenshots/2.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/NZBGet/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/NZBGet/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, { "name": "Nextcloud", "description": "Nextcloud is an open-source, self-hosted file share and collaboration platform, similar to Dropbox. It offers features such as file sharing, syncing, encryption, and collaboration tools. With its extensible app ecosystem, you can tailor your cloud storage service to your needs. Nextcloud is compatible with numerous platforms and can be integrated with many IT infrastructure systems.", @@ -934,388 +125,1816 @@ function list() { "amd64", "arm64" ] - }, - { - "name": "OhMyForm", - "description": "OhMyForm is a free, open-source form creation software. It offers a range of features for creating, administering, analyzing, and distributing beautiful, embeddable forms for various purposes such as recruiting, market research, and surveys. OhMyForm allows for self-hosting with no installation fees or monthly charges.", - "url": "", - "longDescription": "

OhMyForm is a free, open-source software that allows you to craft beautiful forms in seconds for various purposes such as recruiting, market research, surveys, and more. It offers a user-friendly interface and features that make creating, administering, analyzing, and distributing forms straightforward.

Key features of OhMyForm include its wide variety of built-in tools, the ability to create embeddable forms, and a powerful community of contributors that constantly improve and vet the platform. As open-source software, OhMyForm is not only always improving but also completely free.

One of the advantages of OhMyForm is the ability to host it yourself, ensuring no installation fees or monthly charges. This commitment to being 100% open-source allows users to maintain full control over their forms and data.

", - "tags": [ - "productivity", - "open-source", - "self-hosted", - "form creation", - "surveys", - "recruiting", - "market research", - "embeddable forms" - ], - "repository": "https://github.com/ohmyform/ohmyform", - "image": "https://hub.docker.com/r/ohmyform/ohmyform", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/OhMyForm/screenshots/1.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/OhMyForm/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/OhMyForm/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Ombi", - "description": "Ombi is an open-source, self-hosted web application that enables Plex or Emby users to request content. It offers features like user management, a request system, notification system, and automatic updates. Ombi is compatible with popular platforms such as Plex, Emby, Sonarr, Radarr, and Tautulli. It can be run on Windows, Linux, MacOS, and Docker.", - "url": "", - "longDescription": "

Ombi is an open-source, self-hosted web application that enables you to give your shared Plex or Emby users the ability to request content. It's an intuitive interface between your media server and the users.

Key features of Ombi include user management, a request system, notification system, and automatic updates. Ombi can be integrated with popular platforms such as Plex, Emby, Sonarr, Radarr, and Tautulli, making it an essential tool for managing requests for media content.

Ombi is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", - "tags": [ - "media", - "request", - "library", - "open-source", - "self-hosted", - "web application", - "plex", - "emby", - "request system", - "media content", - "windows", - "linux", - "macos", - "docker" - ], - "repository": "https://github.com/Ombi-app/Ombi", - "image": "https://hub.docker.com/r/linuxserver/ombi", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Ombi/screenshots/1.jpg" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Ombi/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Ombi/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "PhotoPrism", - "description": "PhotoPrism is an open-source personal photo management tool that uses smart search, automated tagging, and geolocation to help organize your photos. It supports various image formats, generates thumbnails, and converts RAW images. PhotoPrism works across various platforms and offers a private, self-hosted solution for managing your photos. Start using PhotoPrism today for your photo management needs.", - "url": "", - "longDescription": "

PhotoPrism is an open-source personal photo management tool that makes use of the latest technologies to provide an easy and intuitive way to keep your photos organized. It provides a web-based platform to browse, organize, and share your personal photo collection.

With features like smart search, automated tagging, and geolocation, PhotoPrism makes it easy to find and group your photos. It supports various image formats and RAW files from high-quality cameras. PhotoPrism can also automatically generate thumbnails and convert RAW images.

Available for Windows, Linux, MacOS, and other platforms, PhotoPrism offers a private, self-hosted solution for your photo management needs. Start using PhotoPrism today to take control of your photo collection!

", - "tags": [ - "photo management", - "image organizer", - "smart search", - "automated tagging", - "geolocation", - "thumbnails", - "RAW images", - "self-hosted", - "windows", - "linux", - "macos", - "photoprism" - ], - "repository": "https://github.com/photoprism/photoprism", - "image": "https://hub.docker.com/r/photoprism/photoprism", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Photoprism/screenshots/1.jpg", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Photoprism/screenshots/2.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Photoprism/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Photoprism/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Plex", - "description": "Plex organizes all of your video, and music collections, and gives you instant access to them on all of your devices. With the free Plex Media Server software on your home computer and Plex for iOS, you can enjoy all of your personal media on your iPhone, iPad or iPod touch, and easily share it with friends and family. Plex also makes your media look beautiful with rich descriptions, artwork, and other related information. With an optional premium Plex Pass subscription, you can even sync videos, music, and photos to your smartphones and tablets to enjoy while offline. Parental controls, premium music features, music videos, trailers and extras, and powerful management tools are also part of our premium offering. Getting up and running is fast and simple, so get started now!", - "url": "", - "longDescription": "

Plex is a comprehensive media solution that organizes your video and music collections, giving you instant access across all your devices. With the free Plex Media Server software installed on your home computer and Plex's iOS app, you can enjoy your personal media on your iPhone, iPad, or iPod touch, and conveniently share it with your friends and family.

Plex is not just about easy access, it also enhances your media collection by adding rich descriptions, artwork, and other related information, making your media look visually appealing. If you choose to subscribe to the optional premium Plex Pass, you get the added ability to sync videos, music, and photos to your smartphones and tablets for offline enjoyment.

Premium features also include parental controls, enhanced music features, access to music videos, trailers, extras, and robust management tools. Starting with Plex is straightforward and quick. Get started today and transform your media experience!

", - "tags": [ - "media", - "movies", - "streaming", - "tv", - "music", - "photos", - "videos", - "audiobooks", - "podcasts", - "dlna", - "chromecast", - "android", - "ios", - "roku", - "firetv", - "smarttv", - "web", - "browser", - "kodi", - "emby", - "plex", - "media browser", - "media server", - "media streaming", - "media player", - "media center", - "media management", - "media organizer", - "media collection", - "media library", - "media manager", - "media sharing", - "media transcoding", - "media casting", - "media casting", - "media casting" - ], - "repository": "https://github.com/plex/plex", - "image": "https://hub.docker.com/r/linuxserver/plex", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Plex/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Plex/screenshots/2.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Plex/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Plex/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Radarr", - "description": "Radarr is an automated movie download application, similar to CouchPotato. It helps you to manage your movie collection with features like metadata fetching, trailer linking, and integration with popular download clients. Radarr works across Windows, Linux, MacOS and has a mobile-friendly web interface. Start using Radarr now to automate and enhance your movie downloading and management process.", - "url": "", - "longDescription": "

Radarr is an independent fork of Sonarr reworked for automatically downloading movies via Usenet and BitTorrent. The project was inspired by other Usenet/BitTorrent movie downloaders such as CouchPotato.

Radarr provides a sleek, customizable interface to manage your movie collection, offering features like trailer linking, metadata fetching, and more. The software integrates with popular download clients and can automate your movie download process.

Radarr supports a variety of platforms including Windows, Linux, and MacOS, and also offers a mobile-friendly web interface. Setting up Radarr is straightforward. Get started today to streamline your movie downloading and management experience!

", - "tags": [ - "download", - "movies", - "torrent", - "usenet", - "automated", - "downloader", - "media", - "collection", - "usenet", - "bittorrent", - "windows", - "linux", - "macos", - "web interface", - "metadata", - "movie management", - "movie collection", - "radarr" - ], - "repository": "https://github.com/Radarr/Radarr", - "image": "https://hub.docker.com/r/linuxserver/radarr", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Radarr/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Radarr/screenshots/2.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Radarr/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Radarr/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Readarr", - "description": "Readarr is an open-source, self-hosted PVR for managing and downloading ebooks. It offers features like adding favorite authors, automatic book searching, calendar integration, and importing existing libraries. Readarr supports integration with popular download clients and can send notifications. It can be run on Windows, Linux, MacOS, and Docker.", - "url": "", - "longDescription": "

Readarr is an open-source, self-hosted PVR (Personal Video Recorder) for managing and downloading ebooks. It's built off of the Radarr, Sonarr, and Lidarr platforms and brings the same powerful features to the world of ebooks.

Key features of Readarr include the ability to add your favorite authors, automatic book searching, calendar integration, and the ability to import existing libraries. It supports integration with popular download clients and can send notifications via a number of platforms.

Readarr is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", - "tags": [ - "download", - "ebooks", - "readarr", - "open-source", - "self-hosted", - "PVR", - "book management", - "download", - "windows", - "linux", - "macos", - "docker" - ], - "repository": "https://github.com/Readarr/Readarr", - "image": "https://hub.docker.com/r/linuxserver/readarr", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Readarr/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Readarr/screenshots/2.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Readarr/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Readarr/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Sonarr", - "description": "Sonarr is an automated TV show manager that can search, download, and manage your TV series. It offers features like automatic quality upgrades, episode tracking, and metadata fetching. Sonarr works across various platforms including Windows, Linux, MacOS, and has a mobile-friendly web interface. Start using Sonarr now to automate your TV show management process.", - "url": "", - "longDescription": "

Sonarr is a multi-platform app to search, download, and manage TV shows. It automates the process of searching for new episodes, and can automatically download these files with your preferred download software.

Sonarr offers features such as automatic quality upgrades, series and episode tracking, and metadata fetching to enrich your media library. The interface is user-friendly and mobile-responsive, ensuring you can manage your TV shows easily on any device.

Available for Windows, Linux, and MacOS, Sonarr makes the TV show management process easy and efficient. Get started with Sonarr today and transform your media management experience!

", - "tags": [ - "download", - "tv shows", - "torrent", - "usenet", - "automated", - "manager", - "media", - "collection", - "windows", - "linux", - "macos", - "web interface", - "metadata", - "episode tracking", - "quality upgrades", - "sonarr" - ], - "repository": "https://github.com/Sonarr/Sonarr", - "image": "https://hub.docker.com/r/linuxserver/sonarr", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Sonarr/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Sonarr/screenshots/2.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Sonarr/screenshots/3.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Sonarr/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Sonarr/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Tandoor", - "description": "Tandoor is a recipe manager that allows you to manage your ever growing collection of digital recipes.", - "url": "", - "longDescription": "

Tandoor Recipes is the self hosted recipe manager with meal planning, shopping lists and cookbook collections.

The days of storing recipes on paper cards is in the past and what better way to preserve older recipes that were handed down then to log them into a digital, self hosted recipe manager where you can access them anywhere?

Tandoor Recipes is much more than a digital recipe reference archive, it's a complete meal planning power house.

", - "tags": [ - "recipes", - "meals", - "shopping", - "planning", - "cookbook", - "docker", - "pwa" - ], - "repository": "https://github.com/TandoorRecipes/recipes", - "image": "https://hub.docker.com/r/vabene1111/recipes", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Tandoor/screenshots/1.png", - "https://azukaar.github.io/cosmos-servapps-official/servapps/Tandoor/screenshots/2.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Tandoor/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Tandoor/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Transmission", - "description": "Transmission is an open-source, cross-platform BitTorrent client. It is widely praised for its minimal resource usage, ease-of-use, and performance. Transmission provides features like built-in encryption, webseed support, peer exchange, automatic port mapping, and individual torrent speed limit settings. It supports Windows, Linux, MacOS, and also offers a web interface for remote control.", - "url": "", - "longDescription": "

Transmission is a cross-platform BitTorrent client that is open-source, volunteer-based, and free from advertisements. It is highly regarded for its low resource usage, simplicity, and performance.

With its intuitive interface, Transmission allows users to quickly and easily download and share files via the BitTorrent protocol. Its standout features include built-in encryption, webseed support, peer exchange, automatic port mapping, and the ability to set speed limits for individual torrents.

Transmission is available for a variety of platforms including Windows, Linux, and MacOS. It also provides a web interface for remote control, making it a popular choice among users looking for a lightweight, reliable BitTorrent client.

", - "tags": [ - "download", - "torrent", - "bittorrent", - "downloader", - "open-source", - "cross-platform", - "file sharing", - "peer-to-peer", - "p2p", - "transmission", - "windows", - "linux", - "macos", - "web interface" - ], - "repository": "https://github.com/transmission/transmission", - "image": "https://hub.docker.com/r/linuxserver/transmission", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Transmission/screenshots/1.jpg" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Transmission/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Transmission/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "Uptime Kuma", - "description": "Uptime Kuma is an open-source, self-hosted monitoring tool for tracking the uptime of online services. It offers status checks for various services, detailed statistics with charts, and multiple notification methods. Uptime Kuma is compatible with Windows, Linux, MacOS, and Docker.", - "url": "", - "longDescription": "

Uptime Kuma is an open-source, self-hosted monitoring tool that allows users to monitor their online services and get alerts when they go down or become unresponsive. This robust yet user-friendly tool is designed to help you keep track of your services' uptime.

Key features of Uptime Kuma include status checking for various services including HTTP(s), TCP, and ICMP, detailed statistics with charts, and multiple notification methods (like email, Slack, Telegram, etc.). Its clean, intuitive user interface makes setup and management of monitored services easy.

Uptime Kuma is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", - "tags": [ - "technical", - "administration", - "server", - "open-source", - "self-hosted", - "monitoring", - "uptime", - "service status", - "notifications", - "windows", - "linux", - "macos", - "docker" - ], - "repository": "https://github.com/louislam/uptime-kuma", - "image": "https://hub.docker.com/r/louislam/uptime-kuma", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/UptimeKuma/screenshots/1.jpg", - "https://azukaar.github.io/cosmos-servapps-official/servapps/UptimeKuma/screenshots/2.jpg" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/UptimeKuma/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/UptimeKuma/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] - }, - { - "name": "WordPress", - "description": "WordPress is a free, open-source content management system based on PHP and MySQL. Known for its flexibility and ease-of-use, it supports a range of website types with thousands of plugins and themes. WordPress features a robust administrative dashboard for website creation, modification, and management. It is widely supported across various hosting platforms.", - "url": "", - "longDescription": "

WordPress is a free and open-source content management system (CMS) based on PHP and MySQL. It is one of the most popular website management or blogging system in use on the Web, supporting more than 60 million websites.

WordPress allows users to create and edit websites through a central administrative dashboard, which includes a text editor for modifying content, menus and various design elements. It offers thousands of themes and plugins that can enhance functionality and customization options, making it suitable for a variety of website types, from personal blogs to online stores.

With its vast community, WordPress users have access to a plethora of resources, tutorials, and guides. Start your website journey with WordPress today!

", - "tags": [ - "blogging", - "cms", - "website management", - "php", - "mysql", - "themes", - "plugins", - "self-hosted", - "wordpress" - ], - "repository": "https://github.com/WordPress/WordPress", - "image": "https://hub.docker.com/_/wordpress", - "screenshots": [ - "https://azukaar.github.io/cosmos-servapps-official/servapps/Wordpress/screenshots/1.png" - ], - "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Wordpress/icon.png", - "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Wordpress/cosmos-compose.json", - "supported_architectures": [ - "amd64", - "arm64" - ] } - ] - } - }, - "status": "OK" - }) + ], + "all": { + "cosmos-cloud": [ + { + "name": "Audiobookshelf", + "description": "Audiobookshelf is a self-hosted audiobook and podcast server.", + "url": "", + "longDescription": "

Audiobookshelf is an open-source, self-hosted, audiobook and podcast server. It features an Android and iOS app for streaming your library, multi-user support, storing progress per user, and syncing across devices.

It also includes various audiobook management services like metadata fetching, chapter editing tools, and media merging.

", + "tags": [ + "e-book", + "library", + "audiobook", + "open-source", + "management", + "audiobookshelf", + "docker", + "linux", + "ios", + "android" + ], + "repository": "https://github.com/advplyr/audiobookshelf", + "image": "https://hub.docker.com/r/advplyr/audiobookshelf", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Audiobookshelf/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Audiobookshelf/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Audiobookshelf/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Audiobookshelf/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Bazarr", + "description": "Bazarr is an automated subtitle download application designed to complement Sonarr and Radarr. It simplifies the process of finding and downloading subtitles in various languages. Bazarr supports Windows, Linux, MacOS and provides a mobile-friendly web interface. If you're using Sonarr and Radarr, Bazarr can enhance your media management experience.", + "url": "", + "longDescription": "

Bazarr is a companion application to Sonarr and Radarr that manages and downloads subtitles based on your requirements. It was designed with the aim to make it easier for users to find and download subtitles for their media content.

Bazarr provides a simple and efficient interface to manage your subtitle collection, supporting many languages and integrating with popular subtitle providers. The software works seamlessly with Sonarr and Radarr to provide a unified experience for managing your media.

Bazarr supports a variety of platforms including Windows, Linux, and MacOS, and also offers a mobile-friendly web interface. Setting up Bazarr is easy, making it a must-have tool for anyone using Sonarr and Radarr.

", + "tags": [ + "download", + "subtitle", + "automation", + "downloader", + "media", + "collection", + "sonarr", + "radarr", + "windows", + "linux", + "macos", + "web interface", + "movie management", + "media management", + "bazarr" + ], + "repository": "https://github.com/morpheus65535/bazarr", + "image": "https://hub.docker.com/r/linuxserver/bazarr", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Bazarr/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Bazarr/screenshots/2.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Bazarr/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Bazarr/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Calibre", + "description": "Calibre is an open-source e-book management tool that allows users to organize, save, and manage e-books of various formats. It supports a wide range of e-book formats and offers features like format conversion, e-book syncing, news feeds from web sources, a built-in e-book viewer, and a server for online access.", + "url": "", + "longDescription": "

Calibre is a powerful, open-source e-book management tool. It allows users to organize, save and manage e-books of various formats. Calibre supports a wide range of e-book formats including EPUB, Kindle, PDF, and more.

With its easy-to-use interface, Calibre allows users to convert e-books from different formats, sync e-books with e-book readers, and even provides news feeds from web sources. Calibre also features a built-in e-book viewer and a server for online access to your book collection.

Calibre is available for a variety of platforms, including Windows, Linux, and MacOS.

", + "tags": [ + "e-book", + "library", + "reader", + "open-source", + "cross-platform", + "management", + "calibre", + "windows", + "linux", + "macos" + ], + "repository": "https://github.com/kovidgoyal/calibre", + "image": "https://hub.docker.com/r/linuxserver/calibre", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Calibre-web", + "description": "Calibre-web is a web application providing a clean interface for browsing, reading, and downloading eBooks using an existing Calibre database. It offers features like categorization, a browser-based eBook reader, sending eBooks to Kindle devices, user management, and Goodreads integration.", + "url": "", + "longDescription": "

Calibre-web is a web application providing a clean interface for browsing, reading and downloading eBooks using an existing Calibre database. This software is a fork of the original Calibre web with several additional features and enhancements.

Calibre-web allows users to sort and categorize eBooks, provides a browser-based eBook reader, and even allows the sending of eBooks to Kindle devices. It also supports user management to control access to the eBook collection and offers the ability to interface with Goodreads for book reviews and recommendations.

Calibre-web is compatible with Docker and can be used on any platform that supports Docker.

", + "tags": [ + "e-book", + "library", + "reader", + "web interface", + "management", + "calibre-web", + "docker", + "reading", + "goodreads", + "kindle" + ], + "repository": "https://github.com/janeczku/calibre-web", + "image": "https://hub.docker.com/r/linuxserver/calibre-web", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre-Web/screenshots/1.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre-Web/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Calibre-Web/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Code-Server", + "description": "Code-Server is an open-source tool that enables running Visual Studio Code on a remote server. It provides a full VS Code experience, secure remote access, and compatibility with VS Code extensions. Code-Server is compatible with Windows, Linux, MacOS, and Docker.", + "url": "", + "longDescription": "

Code-Server is an open-source project that allows developers to run Visual Studio Code, a popular development environment, on any machine remotely. This makes it possible to code on your cloud server, which can be particularly beneficial when dealing with large datasets, complex computations, or restricted local resources.

Key features of Code-Server include full Visual Studio Code experience, secure access over SSH or HTTPS, and compatibility with VS Code extensions. It is also designed to be easy to install and get up and running.

Code-Server is available on various platforms including Windows, Linux, and MacOS, and it supports Docker, making it a highly versatile tool for developers across different environments.

", + "tags": [ + "development", + "visual studio code", + "code-server", + "open-source", + "cross-platform", + "VS Code", + "development environment", + "remote coding", + "SSH", + "HTTPS", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/cdr/code-server", + "image": "https://hub.docker.com/r/codercom/code-server", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/CodeServer/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/CodeServer/screenshots/2.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/CodeServer/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/CodeServer/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Deluge", + "description": "Deluge is a lightweight, open-source BitTorrent client known for its extensibility and low resource demand. It supports multiple BitTorrent protocols, offers a web interface for remote control, and includes features like encryption, peer exchange, speed limits, and proxy support. Deluge is compatible with Windows, Linux, MacOS, and Docker.", + "url": "", + "longDescription": "

Deluge is a lightweight, open-source BitTorrent client. It's highly extendable via a rich collection of plugins and is noted for its multi-platform compatibility and low resource demand.

Key features include support for a wide range of BitTorrent protocols, a web interface for remote control, encryption, peer exchange, speed limits, and proxy support. With its intuitive interface, users can easily download and share files via the BitTorrent protocol.

Deluge is compatible with various platforms, including Windows, Linux, and MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", + "tags": [ + "download", + "torrent", + "bittorrent", + "cross-platform", + "BitTorrent client", + "file sharing", + "peer-to-peer", + "p2p", + "encryption", + "web interface", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/deluge-torrent/deluge", + "image": "https://hub.docker.com/r/linuxserver/deluge", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Deluge/screenshots/1.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Deluge/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Deluge/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Docker Mailserver", + "description": "Docker Mailserver is a full-featured, open-source mailserver solution that runs on Docker. It supports various protocols such as SMTP, IMAP, POP3, and LDAP, and includes features such as spam protection, antivirus, DKIM signing, and automated SSL/TLS certificates. Docker Mailserver can be run on platforms that support Docker, including Linux, MacOS, and Windows.", + "url": "", + "longDescription": "

Docker Mailserver is a full-featured, open-source mailserver solution that is designed to run on Docker. It provides a comprehensive set of tools and features needed to run your own mailserver in a production environment.

Key features of Docker Mailserver include support for various protocols such as SMTP, IMAP, POP3, and LDAP. It also includes SpamAssassin for spam protection, ClamAV for antivirus, Postfix for SMTP, and Dovecot for IMAP/POP3. It also supports DKIM signing to authenticate your email and prevent phishing, and provides automated SSL/TLS certificates via Let's Encrypt.

Docker Mailserver is designed to be run on any platform that supports Docker, including Linux, MacOS, and Windows.

", + "tags": [ + "email", + "mail server", + "SMTP", + "docker mailserver", + "open-source", + "mail server", + "docker", + "IMAP", + "POP3", + "LDAP", + "spam protection", + "antivirus", + "DKIM", + "SSL/TLS", + "linux", + "macos", + "windows" + ], + "repository": "https://github.com/docker-mailserver/docker-mailserver", + "image": "https://hub.docker.com/r/mailserver/docker-mailserver", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/DockerMailServer/screenshots/1.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/DockerMailServer/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/DockerMailServer/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Dozzle", + "description": "Dozzle is a real-time log viewer for docker containers.", + "url": "", + "longDescription": "

Dozzle is a small lightweight application with a web based interface to monitor Docker logs. It doesn’t store any log files. It is for live monitoring of your container logs only.

", + "tags": [ + "dozzle", + "open-source", + "self-hosted", + "log viewer" + ], + "repository": "https://github.com/amir20/dozzle", + "image": "https://hub.docker.com/r/amir20/dozzle", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Dozzle/screenshots/1.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Dozzle/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Dozzle/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Duplicati", + "description": "Duplicati is an open-source backup software that creates, encrypts, and stores backups of your files. It offers AES-256 encryption, incremental backups, scheduling, automated backups, and backup verification. Duplicati is compatible with Windows, Linux, MacOS, and Docker.", + "url": "", + "longDescription": "

Duplicati is an open-source backup software designed to secure your data by creating, encrypting, and storing backups of your files. It can backup your files to local drives or various online storage services.

Key features of Duplicati include AES-256 encryption, incremental backups, scheduling, and automated backups. It also supports backup verification, ensuring that your files are not corrupted or lost. Its web-based interface makes it easy to manage and schedule your backups.

Duplicati is compatible with various platforms, including Windows, Linux, and MacOS, and it supports Docker, making it a versatile tool for various environments.

", + "tags": [ + "backup", + "automation", + "encryption", + "open-source", + "cross-platform", + "backup", + "encryption", + "scheduling", + "automated backup", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/duplicati/duplicati", + "image": "https://hub.docker.com/r/duplicati/duplicati", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Duplicati/screenshots/1.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Duplicati/screenshots/2.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Duplicati/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Duplicati/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Emby", + "description": "Emby(https://emby.media/) organizes video, music, live TV, and photos from personal media libraries and streams them to smart TVs, streaming boxes and mobile devices. This container is packaged as a standalone emby Media Server.", + "url": "", + "longDescription": "

Emby is an open-source media system that gives you the power to control the management and streaming of your media content. It offers an alternative to proprietary systems like Plex, empowering users to deliver media content from a dedicated server to various end-user devices through a range of apps.

Key features of Emby include the ability to stream movies, TV shows, music, photos, videos, audiobooks, and podcasts. It also supports various technologies and platforms such as DLNA, Chromecast, Android, iOS, Roku, FireTV, SmartTV, Web browser and Kodi. Emby essentially functions as a comprehensive media browser, server, streaming system, player, center, manager, organizer, and library. In addition to these, it also facilitates media sharing, transcoding, and casting, offering a robust solution for your media needs.

", + "tags": [ + "media", + "server", + "streaming", + "movies", + "tv", + "music", + "photos", + "videos", + "audiobooks", + "podcasts", + "dlna", + "chromecast", + "android", + "ios", + "roku", + "firetv", + "smarttv", + "web", + "browser", + "kodi", + "emby", + "plex", + "media browser", + "media server", + "media streaming", + "media player", + "media center", + "media management", + "media organizer", + "media collection", + "media library", + "media manager", + "media sharing", + "media transcoding", + "media casting", + "media casting", + "media casting" + ], + "repository": "https://github.com/linuxserver/docker-emby", + "image": "https://hub.docker.com/r/linuxserver/emby", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Emby/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Emby/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Emby/screenshots/3.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Emby/screenshots/4.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Emby/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Emby/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Emulator-JS", + "description": "Emulator-JS is an open-source, in-browser multi-system emulator. It allows users to play games from various console systems directly in the browser, facilitated by an intuitive ROM management system. Emulator-JS can be used on any platform that supports a modern web browser, such as Windows, Linux, MacOS, and mobile devices.", + "url": "", + "longDescription": "

Emulator-JS is an open-source, in-browser multi-system emulator. It leverages JavaScript to emulate a wide range of gaming consoles, creating a convenient, accessible, and platform-agnostic gaming experience.

Key features of Emulator-JS include compatibility with multiple console systems, an intuitive ROM management system, and the ability to save game states. Because it's browser-based, Emulator-JS eliminates the need for complex installations or system-specific emulators.

As Emulator-JS runs directly in the browser, it can be used on any platform that supports a modern web browser, including Windows, Linux, MacOS, and even mobile devices. This makes it highly versatile for users across different environments.

", + "tags": [ + "gaming", + "emulation", + "web", + "open-source", + "cross-platform", + "emulator", + "in-browser", + "gaming", + "rom management", + "javascript", + "windows", + "linux", + "macos", + "mobile" + ], + "repository": "https://github.com/EmulatorJS/EmulatorJS", + "image": "https://hub.docker.com/r/linuxserver/emulatorjs", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Emulator-JS/screenshots/1.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Emulator-JS/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Emulator-JS/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Emulator-JS/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Filebrowser", + "description": "Filebrowser is an open-source, self-hosted web application for managing files within your server. It offers features like custom commands, user and permissions management, shareable links, built-in text editor, and media file previews. Filebrowser can be run on any platform that supports Go, including various Linux distributions, Windows, MacOS, and Docker.", + "url": "", + "longDescription": "

Filebrowser is an open-source, self-hosted web application for managing files within your server's file system. The application provides a user-friendly interface, making it simple to navigate, upload, download, and manage your files.

Key features of Filebrowser include support for custom commands, user and permissions management, shareable links, and a built-in text editor. It also supports various media file previews, including video and image file formats.

Filebrowser is designed to run on any platform that supports Go, including various Linux distributions, Windows, and MacOS. Additionally, it can be easily deployed using Docker.

", + "tags": [ + "filebrowser", + "open-source", + "self-hosted", + "file management", + "custom commands", + "permissions management", + "shareable links", + "text editor", + "media previews", + "go", + "linux", + "windows", + "macos", + "docker" + ], + "repository": "https://github.com/filebrowser/filebrowser", + "image": "https://hub.docker.com/r/filebrowser/filebrowser", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Filebrowser/screenshots/1.gif" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Filebrowser/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Filebrowser/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "FreshRSS", + "description": "FreshRSS is an open-source, self-hosted RSS feed aggregator that is lightweight and easy to use. Features include a responsive design, import/export OPML files, multiple themes, filters, categories, multi-user support, and extensibility with plugins. FreshRSS is compatible with Windows, Linux, MacOS, and Docker.", + "url": "", + "longDescription": "

FreshRSS is an open-source, self-hosted RSS feed aggregator. It is lightweight, easy to use, and packed with features. FreshRSS lets you collect, manage, and read your RSS feeds from your own server, offering a high degree of control and privacy.

Key features include a responsive design that works well on desktop and mobile devices, the ability to import/export OPML files, multiple themes, filters, categories, and multi-user support with the ability to manage user roles. Furthermore, it's extensible with plugins for additional functionalities.

FreshRSS is compatible with various platforms, including Windows, Linux, and MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", + "tags": [ + "RSS", + "feed aggregator", + "news", + "freshrss", + "open-source", + "self-hosted", + "responsive", + "OPML", + "multi-user", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/FreshRSS/FreshRSS", + "image": "https://hub.docker.com/r/linuxserver/freshrss", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/FreshRSS/screenshots/1.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/FreshRSS/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/FreshRSS/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Gitea", + "description": "Gitea is a lightweight, open-source Git platform for self-hosted repository management, code collaboration, and issue tracking. It offers an intuitive interface, powerful access control, and integrations with popular development tools.", + "url": "", + "longDescription": "

Gitea is a lightweight, open-source Git platform that provides a self-hosted solution for managing repositories, collaborative code reviews, and issue tracking.

With Gitea, you can easily create and manage Git repositories, track changes, collaborate with team members, and streamline your software development workflow. It offers a simple and intuitive user interface, powerful access control, and a range of features such as code highlighting, pull requests, and issue management.

Gitea is written in Go and is designed to be lightweight, fast, and easy to deploy. It supports multiple authentication methods, including built-in user accounts, LDAP, and OAuth. Gitea also provides integrations with popular development tools and services.

Whether you're a small team or a large organization, Gitea provides a flexible and customizable platform for hosting your Git repositories and managing your software projects.

", + "tags": [ + "development", + "git", + "repository management", + "code collaboration", + "issue tracking", + "go", + "self-hosted", + "gitea" + ], + "repository": "https://github.com/go-gitea/gitea", + "image": "https://hub.docker.com/r/gitea/gitea", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Gitea/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Gitea/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Gitea/screenshots/3.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Gitea/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Gitea/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Grav", + "description": "Grav is an open-source, self-hosted, flat-file content management system (CMS). It offers features like content filtering, multi-language support, flexible templating with Twig, and simple content creation with Markdown. Grav can be extended with plugins and themes. It can be run on Windows, Linux, MacOS, and Docker.", + "url": "", + "longDescription": "

Grav is an open-source, self-hosted, flat-file content management system (CMS). Unlike traditional CMS platforms, Grav does not use a database to store content, making it incredibly lightweight and easy to manage.

Key features of Grav include powerful content filtering, multi-language support, flexible templating with Twig, and simple content creation process with Markdown. Its extendibility with a rich ecosystem of plugins and themes, plus a strong focus on performance, makes Grav a versatile platform for creating all kinds of websites.

Grav is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", + "tags": [ + "web", + "blog", + "code", + "open-source", + "self-hosted", + "CMS", + "flat-file", + "content management", + "twig", + "markdown", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/getgrav/grav", + "image": "https://hub.docker.com/r/getgrav/grav", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Grav/screenshots/1.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Grav/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Grav/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Grocy", + "description": "Grocy is a self-hosted, open-source grocery management solution offering features like stock management with a barcode scanner, recipe management, household chore management, and tracking of purchased items with expiration dates. Grocy is compatible with Windows, Linux, MacOS, and Docker.", + "url": "", + "longDescription": "

Grocy is a self-hosted, open-source grocery management solution designed to help users manage their groceries. It provides a suite of tools for managing shopping lists, recipes, inventory, and chores.

Key features include stock management with a barcode scanner, recipe management, household chore management, and tracking of purchased items with expiration dates. Grocy helps users to avoid waste by providing reminders about due dates of perishable items.

Grocy is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", + "tags": [ + "life", + "groceries", + "list", + "open-source", + "self-hosted", + "grocery", + "management", + "shopping list", + "inventory", + "recipes", + "chores", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/grocy/grocy", + "image": "https://hub.docker.com/r/linuxserver/grocy", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Grocy/screenshots/1.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Grocy/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Grocy/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Handbrake", + "description": "HandBrake is a tool for converting video from nearly any format to a selection of modern, widely supported codecs.", + "url": "", + "longDescription": "

This project implements a Docker container for HandBrake.

The GUI of the application is accessed through a modern web browser (no installation or configuration needed on the client side) or via any VNC client.

A fully automated mode is also available: drop files into a watch folder and let HandBrake process them without any user interaction.

Full documentation is available at https://github.com/jlesage/docker-handbrake.

", + "tags": [ + "media", + "video", + "conversion" + ], + "repository": "https://github.com/jlesage/docker-handbrake", + "image": "https://hub.docker.com/r/jlesage/handbrake", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Handbrake/screenshots/1.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Handbrake/screenshots/2.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Handbrake/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Handbrake/cosmos-compose.json", + "supported_architectures": [ + "amd64" + ] + }, + { + "name": "Heimdall", + "description": "Heimdall is an open-source, self-hosted dashboard software that provides a central hub for web-based applications and services. Features include a built-in application library, custom themes, multi-user support, and compatibility with desktop and mobile browsers. Heimdall is compatible with Windows, Linux, MacOS, and Docker.", + "url": "", + "longDescription": "

Heimdall is an open-source, self-hosted dashboard software that allows you to organize and access your web-based applications and services all in one place. It's designed to provide a central hub to simplify your web environment.

Key features of Heimdall include the ability to add applications via a built-in library or by creating custom application definitions, custom themes, and the capacity to run on a desktop or mobile browser. It supports multiple users and each user can have their own personalized set of applications.

Heimdall is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", + "tags": [ + "dashboard", + "home", + "icons", + "open-source", + "self-hosted", + "web-based applications", + "services", + "central hub", + "multi-user", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/linuxserver/Heimdall", + "image": "https://hub.docker.com/r/linuxserver/heimdall", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Heimdall/screenshots/1.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Heimdall/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Heimdall/screenshots/3.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Heimdall/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Heimdall/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Homarr", + "description": "Homarr is an open-source, self-hosted dashboard software that provides a central hub for web-based applications and services. Features include a built-in application library, custom themes, multi-user support, and compatibility with desktop and mobile browsers. Homarr is compatible with Windows, Linux, MacOS, and Docker.", + "url": "", + "longDescription": "

Homarr is an open-source, self-hosted dashboard software that allows you to organize and access your web-based applications and services all in one place. It's designed to provide a central hub to simplify your web environment.

Key features of Homarr include the ability to add applications via a built-in library or by creating custom application definitions, custom themes, and the capacity to run on a desktop or mobile browser. It supports multiple users and each user can have their own personalized set of applications.

Homarr is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", + "tags": [ + "dashboard", + "home", + "icons", + "open-source", + "self-hosted", + "web-based applications", + "services", + "central hub", + "multi-user", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/ajnart/homarr", + "image": "https://hub.docker.com/r/homarr", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Homarr/screenshots/1.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Homarr/screenshots/2.webp" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Homarr/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Homarr/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Home Assistant", + "description": "Home Assistant is an open-source home automation platform that focuses on privacy and local control. It allows you to control all your devices from a single interface, integrating with a large number of devices and services. Home Assistant offers advanced automation capabilities, running perfectly on a Raspberry Pi or a local server. Start using Home Assistant today for a comprehensive home automation solution.", + "url": "", + "longDescription": "

Home Assistant is an open-source home automation platform focused on privacy and local control. It allows you to control all your devices from a single, unified interface. It is powered by a worldwide community of tinkerers and DIY enthusiasts, perfect to run on a Raspberry Pi or a local server.

Home Assistant integrates with a large number of different devices and services, providing the user with a powerful and flexible home automation control center. In addition to its powerful, flexible features, it provides advanced automation capabilities to help make your life easier.

With support for a vast array of devices and services, Home Assistant can be the one-stop solution for all your home automation needs. Get started with Home Assistant today and take control of your home automation!

", + "tags": [ + "smart home", + "home automation", + "IoT", + "Raspberry Pi", + "local server", + "privacy", + "control", + "automation", + "devices", + "services", + "home assistant" + ], + "repository": "https://github.com/home-assistant/core", + "image": "https://hub.docker.com/r/homeassistant/home-assistant", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/HomeAssistant/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/HomeAssistant/screenshots/2.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/HomeAssistant/screenshots/3.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/HomeAssistant/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/HomeAssistant/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Homebox", + "description": "Homebox is the inventory and organization system built for the Home User.", + "url": "", + "longDescription": "

Homebox is the inventory and organization system built for the Home User! With a focus on simplicity and ease of use, Homebox is the perfect solution for your home inventory, organization, and management needs.

", + "tags": [ + "home", + "homebox", + "organization", + "inventory", + "management", + "docker", + "linux" + ], + "repository": "https://github.com/hay-kot/homebox", + "image": "https://ghcr.io/hay-kot/homebox:latest", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Homebox/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Homebox/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Homebox/screenshots/3.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Homebox/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Homebox/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Immich", + "description": "Immich - High performance self-hosted photo and video backup solution", + "url": "", + "longDescription": "

Immich is an open-source personal photo management tool that makes use of the latest technologies to provide an easy and intuitive way to keep your photos organized. It provides a web-based platform to browse, organize, and share your personal photo collection.

With features like smart search, automated tagging, and geolocation, Immich makes it easy to find and group your photos. It supports various image formats and RAW files from high-quality cameras. Immich can also automatically generate thumbnails and convert RAW images.

Available for Windows, Linux, MacOS, and other platforms, Immich offers a private, self-hosted solution for your photo management needs. Start using Immich today to take control of your photo collection!

", + "tags": [ + "photo management", + "image organizer", + "smart search", + "automated tagging", + "geolocation", + "thumbnails", + "RAW images", + "self-hosted", + "windows", + "linux", + "macos", + "Immich" + ], + "repository": "https://github.com/Immich/Immich", + "image": "https://hub.docker.com/r/Immich/Immich", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Immich/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Immich/screenshots/2.webp", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Immich/screenshots/3.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Immich/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Immich/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Jellyfin", + "description": "Jellyfin is a Free Software Media System that puts you in control of managing and streaming your media. It is an alternative to the proprietary Plex, to provide media from a dedicated server to end-user devices via multiple apps.", + "url": "", + "longDescription": "

Jellyfin is an open-source media system that gives you the power to control the management and streaming of your media content. It offers an alternative to proprietary systems like Plex, empowering users to deliver media content from a dedicated server to various end-user devices through a range of apps.

Key features of Jellyfin include the ability to stream movies, TV shows, music, photos, videos, audiobooks, and podcasts. It also supports various technologies and platforms such as DLNA, Chromecast, Android, iOS, Roku, FireTV, SmartTV, Web browser, Kodi, and Emby. Jellyfin essentially functions as a comprehensive media browser, server, streaming system, player, center, manager, organizer, and library. In addition to these, it also facilitates media sharing, transcoding, and casting, offering a robust solution for your media needs.

", + "tags": [ + "media", + "server", + "streaming", + "movies", + "tv", + "music", + "photos", + "videos", + "audiobooks", + "podcasts", + "dlna", + "chromecast", + "android", + "ios", + "roku", + "firetv", + "smarttv", + "web", + "browser", + "kodi", + "emby", + "plex", + "media browser", + "media server", + "media streaming", + "media player", + "media center", + "media management", + "media organizer", + "media collection", + "media library", + "media manager", + "media sharing", + "media transcoding", + "media casting", + "media casting", + "media casting" + ], + "repository": "https://github.com/jellyfin/jellyfin", + "image": "https://hub.docker.com/r/linuxserver/jellyfin", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyfin/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyfin/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyfin/screenshots/3.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyfin/screenshots/4.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyfin/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyfin/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Jellyseerr", + "description": "Jellyseerr is a free and open source software application for managing requests for your media library. It is a a fork of Overseerr built to bring support for Jellyfin & Emby media servers!", + "url": "", + "longDescription": "

Jellyseerr is a free and open source software application for managing requests for your media library. It is a a fork of Overseerr built to bring support for Jellyfin & Emby media servers!

", + "tags": [ + "media", + "request", + "library", + "open-source", + "self-hosted", + "web application", + "plex", + "emby", + "jellyfin", + "request system", + "media content", + "windows", + "linux", + "macos", + "docker", + "radarr", + "sonarr" + ], + "repository": "https://github.com/Fallenbagel/jellyseerr", + "image": "https://hub.docker.com/r/fallenbagel/jellyseerr", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyseerr/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyseerr/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyseerr/screenshots/3.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyseerr/screenshots/4.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyseerr/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Jellyseerr/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Joplin", + "description": "Joplin is a free, open-source note-taking and to-do application that supports markdown and end-to-end encryption. It offers capabilities such as tagging, searching, and modifying notes, and can sync with various cloud platforms. It features an extensible plugin system, allowing for tailored functionality. Joplin is compatible across multiple platforms including Windows, Linux, MacOS, iOS, and Android.", + "url": "", + "longDescription": "

Joplin is a free and open-source note-taking and to-do application, which can handle a large number of notes organised into notebooks. The notes are searchable, can be copied, tagged and modified directly from the applications or from your own text editor. It also supports markdown, with inline previewing.

Joplin offers end-to-end encryption and can synchronize with various cloud platforms, making it a secure choice for your note-taking needs. With its API, Joplin can be extended with plugins for custom functionality, further tailoring your note management experience.

Available for Windows, Linux, MacOS, iOS, and Android, Joplin is flexible to fit a variety of environments and workflows. Start using Joplin today to organize your thoughts and tasks in a secure and efficient manner!

", + "tags": [ + "productivity", + "note-taking", + "to-do", + "markdown", + "encryption", + "syncing", + "windows", + "linux", + "macos", + "ios", + "android", + "self-hosted", + "joplin" + ], + "repository": "https://github.com/laurent22/joplin", + "image": "https://hub.docker.com/r/joplin/server", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Joplin/screenshots/1.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Joplin/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Joplin/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Joplin/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "KitchenOwl", + "description": "KitchenOwl helps you organize your grocery life.", + "url": "", + "longDescription": "

KitchenOwl is a smart grocery list and recipe manager.

Easily add items to your shopping list before you go shopping. You can also create recipes and get suggestions on what you want to cook.

Track your expenses so you know how much you've spent.

", + "tags": [ + "recipes", + "meals", + "shopping", + "planning", + "expenses", + "docker" + ], + "repository": "https://github.com/tombursch/kitchenowl", + "image": "https://hub.docker.com/r/tombursch/kitchenowl", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Kitchenowl/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Kitchenowl/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Kitchenowl/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Kitchenowl/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "LSDVR", + "description": "Automatic VOD recording", + "url": "", + "longDescription": "Automatic VOD recording around when the stream goes live, instead of checking it every minute like many other scripts do. Because of notification delays, the stream usually starts capturing after ~2 minutes after the stream goes live. Cyclic recording, as in when a specified amount or storage per streamer is reached, the oldest stream gets deleted. Tons of metadata, maybe too much. Stores info about games played, stream titles, duration, if the stream got muted from copyrighted music, etc. Viewer count logging with graphs. Chapters (titles and games) are written to the final video file. Video player with chat playback. Video cutter with chapter display for easy exporting, also cuts the downloaded chat for synced rendering. Notifications with optional speech when the website is open, get stream live notifications far earlier than the mobile app does. Writes a losslesscut compatible csv file for the full VOD, so you don't have to find all the games. Uses `ts` instead of `mp4` so if the stream or program crashes, the file won't be corrupted. Audio only support. Optionally either dumps chat while capturing or downloads the chat file after it's done. Basic tools for downloading any VOD, chat, or clip. Can be set to automatically download the whole stream chat to a JSON file, to be used in my twitch-vod-chat webapp or automatically burned in with TwitchDownloader. Basic webhook support for external scripting. Notifications over the browser, telegram, pushover, and discord. Mobile friendly site with PWA. Exporting of videos to external file, SFTP, and YouTube. Can be enabled for all finished captures Can be run for an entire channel at once

", + "tags": [ + "twitch", + "youtube", + "download", + "videos", + "vod", + "media" + ], + "repository": "https://github.com/alexta69/metube", + "image": "https://github.com/alexta69/metube/pkgs/container/metube", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/LSDVR/screenshots/1.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/LSDVR/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/LSDVR/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Lemmy", + "description": "Lemmy is an open-source, self-hosted, federated link aggregator similar to Reddit. It offers community formation, moderation tools, content voting, and supports commenting and private messaging between users. Lemmy can be run on Windows, Linux, MacOS, and Docker.", + "url": "", + "longDescription": "

Lemmy is an open-source, self-hosted, federated link aggregator application similar to Reddit, which allows users to create their own communities and share links and posts with others.

Key features of Lemmy include its ability to form federated link-aggregator communities, moderation tools, and the ability to vote on content. It also supports commenting and private messaging between users. Lemmy is designed to consume minimal resources and can be easily self-hosted on small servers.

Lemmy is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", + "tags": [ + "social", + "federation", + "reddit", + "open-source", + "self-hosted", + "federated", + "link aggregator", + "community", + "moderation", + "content voting", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/LemmyNet/lemmy", + "image": "https://hub.docker.com/r/dessalines/lemmy", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Lemmy/screenshots/1.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Lemmy/screenshots/2.webp" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Lemmy/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Lemmy/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Lidarr", + "description": "Lidarr is an automated music manager for maintaining your music library. It does this by finding and automatically downloading your desired music tracks. It integrates with popular download clients and supports metadata fetching from multiple music databases. With Lidarr, your music downloading and organization process can be streamlined and automated. It supports various platforms and has a mobile-friendly web interface for easy access. Get started with Lidarr now and enhance your music management experience!", + "url": "", + "longDescription": "

Lidarr is an automated music collection manager that can find, add, and manage music in your collection. With Lidarr, you can automatically search for new albums and singles from your favorite artists, and automatically download them to your media server. It is integrated with popular download clients and supports multiple music databases for metadata fetching.

Lidarr is a perfect solution for those who want to automate their music downloading and organization process. It is available for various platforms including Windows, Linux, and MacOS, and has a mobile-friendly web interface that works across different devices.

Setting up Lidarr is straightforward. Whether you are an audiophile with a large collection or someone who just loves listening to music, Lidarr can transform your music management experience!

", + "tags": [ + "download", + "torrent", + "music", + "usenet", + "automation", + "manager", + "media", + "collection", + "download", + "metadata", + "windows", + "linux", + "macos", + "web interface", + "streaming", + "music library", + "music database", + "music management", + "music collection", + "lidarr" + ], + "repository": "https://github.com/lidarr/Lidarr", + "image": "https://hub.docker.com/r/linuxserver/lidarr", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Lidarr/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Lidarr/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Lidarr/screenshots/3.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Lidarr/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Lidarr/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "MKVToolNix", + "description": "MKVToolNix is a set of tools to create, alter and inspect Matroska files.", + "url": "", + "longDescription": "

This project implements a Docker container for MKVToolNix.

The GUI of the application is accessed through a modern web browser (no installation or configuration needed on the client side) or via any VNC client.

", + "tags": [ + "media", + "video", + "conversion" + ], + "repository": "https://github.com/jlesage/docker-mkvtoolnix", + "image": "https://hub.docker.com/r/jlesage/mkvtoolnix", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/MKVToolNix/screenshots/1.jpeg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/MKVToolNix/screenshots/2.jpeg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/MKVToolNix/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/MKVToolNix/cosmos-compose.json", + "supported_architectures": [ + "amd64" + ] + }, + { + "name": "Mastodon", + "description": "Mastodon is a free and open-source self-hosted social networking service. It features decentralization, ability to build your own community, per-post privacy settings, anti-abuse tools, and supports multimedia attachments. Mastodon can be run on any platform that supports Ruby, Node.js, and PostgreSQL, including various Linux distributions and Docker.", + "url": "", + "longDescription": "

Mastodon is a free and open-source self-hosted social networking service. It allows anyone to host their own server node in the network, while interacting with other users in a federated manner. It is similar to Twitter, but is distinguished by its decentralization and ability for users to host their own servers, and its character limit of 500 as opposed to Twitter's 280.

Key features of Mastodon include the ability to build your own community, granular, per-post privacy settings, and anti-abuse tools. It supports a rich variety of multimedia attachments in posts, and you can also choose to use content warnings on your posts for viewer discretion.

Mastodon can be run on any platform that supports Ruby, Node.js, and PostgreSQL, including various Linux distributions and Docker.

", + "tags": [ + "social", + "federation", + "reddit", + "open-source", + "self-hosted", + "federated", + "link aggregator", + "community", + "moderation", + "content voting", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/tootsuite/mastodon", + "image": "https://hub.docker.com/r/tootsuite/mastodon", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Mastodon/screenshots/1.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Mastodon/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Mastodon/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Mastodon/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "MeTube", + "description": "youtube-dl web UI", + "url": "", + "longDescription": "

Web GUI for youtube-dl (using the yt-dlp fork) with playlist support. Allows you to download videos from YouTube and dozens of other sites.

", + "tags": [ + "youtube", + "youtube-dl", + "download", + "videos", + "music", + "media" + ], + "repository": "https://github.com/alexta69/metube", + "image": "https://github.com/alexta69/metube/pkgs/container/metube", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/MeTube/screenshots/1.gif" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/MeTube/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/MeTube/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Mealie", + "description": "Recipe Management For The Modern Household", + "url": "", + "longDescription": "

Mealie is an intuitive and easy to use recipe management app. It's designed to make your life easier by being the best recipes management experience on the web and providing you with an easy to use interface to manage your growing collection of recipes.

Default Password is: MyPassword

", + "tags": [ + "recipes", + "meals", + "shopping", + "planning", + "cookbook", + "docker", + "pwa" + ], + "repository": "https://github.com/mealie-recipes/mealie", + "image": "https://hub.docker.com/r/hkotel/mealie/", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Mealie/screenshots/1.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Mealie/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Mealie/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Minecraft", + "description": "Minecraft is a sandbox video game developed by Mojang Studios that allows players to explore, interact with, and modify a dynamically-generated map made of blocks. Players can build structures, craft items, and interact with the game world in a variety of ways. The game supports multiple gameplay styles and modes, and is available on a wide range of platforms.", + "url": "", + "longDescription": "

Minecraft is a highly popular and critically acclaimed sandbox video game developed by Mojang Studios. It allows players to explore a blocky, procedurally generated 3D world with virtually infinite terrain, and may discover and extract raw materials, craft tools and items, build structures, and interact with the game's various entities.

Gameplay involves players interacting with the game world by placing and breaking various types of blocks in a three-dimensional environment. In this environment, players can build creative structures, creations, and artwork on multiplayer servers and singleplayer worlds across multiple game modes. Minecraft supports a wide range of gameplay styles, including survival mode, creative mode, adventure mode, and spectator mode.

Minecraft is available on multiple platforms, including Windows, MacOS, Linux, and various consoles and mobile devices.

", + "tags": [ + "game servers", + "mojang", + "sandbox", + "game", + "procedurally generated", + "3D", + "multiplayer", + "singleplayer", + "survival", + "creative", + "adventure", + "spectator", + "windows", + "macos", + "linux", + "console", + "mobile" + ], + "repository": "https://www.minecraft.net/", + "image": "https://www.minecraft.net/en-us/about-minecraft", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Minecraft-Server/screenshots/1.webp" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Minecraft-Server/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Minecraft-Server/cosmos-compose.json", + "supported_architectures": [ + "x86", + "amd64", + "arm", + "arm64" + ] + }, + { + "name": "NZBGet", + "description": "NZBGet is a high-performance Usenet downloader that uses NZB files to fetch content. It is designed to use minimal system resources while offering features such as a web-interface, API, automatic post-processing, and RSS feed support. NZBGet works well on various platforms including low powered devices. Start using NZBGet for your Usenet downloads today!", + "url": "", + "longDescription": "

NZBGet is a robust and lightweight Usenet downloader. It can download files from Usenet servers via NZB index files. The software is focused on performance and uses very little system resources, while achieving high download speeds.

NZBGet offers a variety of features including web-interface, API, automatic post-processing, RSS feed support, and more. It is also designed to work well on low powered devices like Raspberry Pi.

Available on multiple platforms including Windows, MacOS, Linux, and others, NZBGet is easy to set up and use. Start using NZBGet today for efficient Usenet downloading!

", + "tags": [ + "download", + "torrent", + "usenet", + "downloader", + "nzb", + "windows", + "linux", + "macos", + "raspberry pi", + "performance", + "rss feed", + "post-processing", + "nzbget" + ], + "repository": "https://github.com/nzbget/nzbget", + "image": "https://hub.docker.com/r/linuxserver/nzbget", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/NZBGet/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/NZBGet/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/NZBGet/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/NZBGet/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Nextcloud", + "description": "Nextcloud is an open-source, self-hosted file share and collaboration platform, similar to Dropbox. It offers features such as file sharing, syncing, encryption, and collaboration tools. With its extensible app ecosystem, you can tailor your cloud storage service to your needs. Nextcloud is compatible with numerous platforms and can be integrated with many IT infrastructure systems.", + "url": "", + "longDescription": "

Nextcloud is a suite of client-server software for creating and using file hosting services. It is functionally similar to Dropbox, but is free and open-source, allowing users to install it on private servers.

Nextcloud provides an array of features including file sharing, syncing, end-to-end encryption, collaboration tools, and more. Its extensible app ecosystem allows you to set up your own cloud storage service to your exact needs. You can also integrate Nextcloud with many known IT infrastructure systems.

Available for Windows, Linux, MacOS, and other platforms, Nextcloud is designed to work in a variety of environments including both on premise and cloud setups. Start using Nextcloud today to control and secure your own private cloud storage!

", + "tags": [ + "storage", + "file sharing", + "syncing", + "encryption", + "collaboration", + "windows", + "linux", + "macos", + "self-hosted", + "nextcloud" + ], + "repository": "https://github.com/nextcloud/server", + "image": "https://hub.docker.com/r/linuxserver/nextcloud", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Nextcloud/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Nextcloud/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Nextcloud/screenshots/3.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Nextcloud/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Nextcloud/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Notifiarr", + "description": "You just found one of the coolest tools on the Internet for a homelab enthusiast. We do notifications.", + "url": "", + "longDescription": "

You just found one of the coolest tools on the Internet for a homelab enthusiast. We do notifications. We do them right. We've been doing then for years and we'll keep doing them for years to come. Notifiarr provides native custom integrations with dozens, maybe hundreds of applications and websites. That means these applications or websites can send data to Notifiarr, and we'll format a message according to your configuration then send it to your chat server.

", + "tags": [ + "notifications", + "rest api", + "curl", + "push notifications" + ], + "repository": "https://github.com/Notifiarr/notifiarr", + "image": "https://hub.docker.com/r/golift/notifiarr", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Notifiarr/screenshots/1.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Notifiarr/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Notifiarr/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "OhMyForm", + "description": "OhMyForm is a free, open-source form creation software. It offers a range of features for creating, administering, analyzing, and distributing beautiful, embeddable forms for various purposes such as recruiting, market research, and surveys. OhMyForm allows for self-hosting with no installation fees or monthly charges.", + "url": "", + "longDescription": "

OhMyForm is a free, open-source software that allows you to craft beautiful forms in seconds for various purposes such as recruiting, market research, surveys, and more. It offers a user-friendly interface and features that make creating, administering, analyzing, and distributing forms straightforward.

Key features of OhMyForm include its wide variety of built-in tools, the ability to create embeddable forms, and a powerful community of contributors that constantly improve and vet the platform. As open-source software, OhMyForm is not only always improving but also completely free.

One of the advantages of OhMyForm is the ability to host it yourself, ensuring no installation fees or monthly charges. This commitment to being 100% open-source allows users to maintain full control over their forms and data.

", + "tags": [ + "productivity", + "open-source", + "self-hosted", + "form creation", + "surveys", + "recruiting", + "market research", + "embeddable forms" + ], + "repository": "https://github.com/ohmyform/ohmyform", + "image": "https://hub.docker.com/r/ohmyform/ohmyform", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/OhMyForm/screenshots/1.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/OhMyForm/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/OhMyForm/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Ombi", + "description": "Ombi is an open-source, self-hosted web application that enables Plex or Emby users to request content. It offers features like user management, a request system, notification system, and automatic updates. Ombi is compatible with popular platforms such as Plex, Emby, Sonarr, Radarr, and Tautulli. It can be run on Windows, Linux, MacOS, and Docker.", + "url": "", + "longDescription": "

Ombi is an open-source, self-hosted web application that enables you to give your shared Plex or Emby users the ability to request content. It's an intuitive interface between your media server and the users.

Key features of Ombi include user management, a request system, notification system, and automatic updates. Ombi can be integrated with popular platforms such as Plex, Emby, Sonarr, Radarr, and Tautulli, making it an essential tool for managing requests for media content.

Ombi is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", + "tags": [ + "media", + "request", + "library", + "open-source", + "self-hosted", + "web application", + "plex", + "emby", + "request system", + "media content", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/Ombi-app/Ombi", + "image": "https://hub.docker.com/r/linuxserver/ombi", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Ombi/screenshots/1.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Ombi/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Ombi/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Overseerr", + "description": "Overseerr is a request management and media discovery tool built to work with your existing Plex ecosystem.", + "url": "", + "longDescription": "

Overseerr is a free and open source software application for managing requests for your media library. It integrates with your existing services, such as Sonarr, Radarr, and Plex.

Overseerr helps you find media you want to watch. With inline recommendations and suggestions, you will find yourself deeper and deeper in a rabbit hole of content you never knew you just had to have.

Overseerr presents you and your users with a request interface that is incredibly easy to understand and use. Users can select the exact seasons they want to watch. Advanced users can use the “Advanced Requests” options to change destination folders and quality profiles.

Overseerr aims to make you and your user's lives more effortless than ever before.

", + "tags": [ + "media", + "request", + "library", + "open-source", + "self-hosted", + "web application", + "plex", + "request system", + "media content", + "windows", + "linux", + "macos", + "docker", + "radarr", + "sonarr" + ], + "repository": "https://github.com/sct/overseerr", + "image": "https://hub.docker.com/r/linuxserver/overseerr", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Overseerr/screenshots/1.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Overseerr/screenshots/2.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Overseerr/screenshots/3.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Overseerr/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Overseerr/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Paperless-ngx", + "description": "Paperless-ngx is a document management system that transforms your physical documents into a searchable online archive so you can keep, well, less paper.", + "url": "", + "longDescription": "

Paperless-ngx is a community-supported open-source document management system that transforms your physical documents into a searchable online archive so you can keep, well, less paper.

This version of Paperless-ngx is configured using PostgreSQL as the database server, as well as Apache, Tika, and Gotenberg servers to provide support for consuming Office documents (Word, Excel, Power Point and their LibreOffice counterparts.

", + "tags": [ + "document", + "management", + "organization", + "archive", + "collection", + "web interface", + "paper", + "docker" + ], + "repository": "https://github.com/paperless-ngx/paperless-ngx", + "image": "https://ghcr.io/paperless-ngx/paperless-ngx", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Paperless-ngx/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Paperless-ngx/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Paperless-ngx/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Paperless-ngx/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "PhotoPrism", + "description": "PhotoPrism is an open-source personal photo management tool that uses smart search, automated tagging, and geolocation to help organize your photos. It supports various image formats, generates thumbnails, and converts RAW images. PhotoPrism works across various platforms and offers a private, self-hosted solution for managing your photos. Start using PhotoPrism today for your photo management needs.", + "url": "", + "longDescription": "

PhotoPrism is an open-source personal photo management tool that makes use of the latest technologies to provide an easy and intuitive way to keep your photos organized. It provides a web-based platform to browse, organize, and share your personal photo collection.

With features like smart search, automated tagging, and geolocation, PhotoPrism makes it easy to find and group your photos. It supports various image formats and RAW files from high-quality cameras. PhotoPrism can also automatically generate thumbnails and convert RAW images.

Available for Windows, Linux, MacOS, and other platforms, PhotoPrism offers a private, self-hosted solution for your photo management needs. Start using PhotoPrism today to take control of your photo collection!

", + "tags": [ + "photo management", + "image organizer", + "smart search", + "automated tagging", + "geolocation", + "thumbnails", + "RAW images", + "self-hosted", + "windows", + "linux", + "macos", + "photoprism" + ], + "repository": "https://github.com/photoprism/photoprism", + "image": "https://hub.docker.com/r/photoprism/photoprism", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Photoprism/screenshots/1.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Photoprism/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Photoprism/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Photoprism/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Plex", + "description": "Plex organizes all of your video, and music collections, and gives you instant access to them on all of your devices. With the free Plex Media Server software on your home computer and Plex for iOS, you can enjoy all of your personal media on your iPhone, iPad or iPod touch, and easily share it with friends and family. Plex also makes your media look beautiful with rich descriptions, artwork, and other related information. With an optional premium Plex Pass subscription, you can even sync videos, music, and photos to your smartphones and tablets to enjoy while offline. Parental controls, premium music features, music videos, trailers and extras, and powerful management tools are also part of our premium offering. Getting up and running is fast and simple, so get started now!", + "url": "", + "longDescription": "

WARNING! We highly advise AGAINST using Plex. It is gradually becoming agressive against the self-hosting community to the point that it might as well become cloud only in the next few years. It is also NOT a selfhosted app as a lof of your data are in the cloud (include analytics about what you watch) and it is not opensource. Instead, consider using Jellyfin, which is selfhosted and opensource unlike Plex.

Plex is a comprehensive media solution that organizes your video and music collections, giving you instant access across all your devices. With the free Plex Media Server software installed on your home computer and Plex's iOS app, you can enjoy your personal media on your iPhone, iPad, or iPod touch, and conveniently share it with your friends and family.

Plex is not just about easy access, it also enhances your media collection by adding rich descriptions, artwork, and other related information, making your media look visually appealing. If you choose to subscribe to the optional premium Plex Pass, you get the added ability to sync videos, music, and photos to your smartphones and tablets for offline enjoyment.

Premium features also include parental controls, enhanced music features, access to music videos, trailers, extras, and robust management tools. Starting with Plex is straightforward and quick. Get started today and transform your media experience!

", + "tags": [ + "media", + "movies", + "streaming", + "tv", + "music", + "photos", + "videos", + "audiobooks", + "podcasts", + "dlna", + "chromecast", + "android", + "ios", + "roku", + "firetv", + "smarttv", + "web", + "browser", + "kodi", + "emby", + "plex", + "media browser", + "media server", + "media streaming", + "media player", + "media center", + "media management", + "media organizer", + "media collection", + "media library", + "media manager", + "media sharing", + "media transcoding", + "media casting", + "media casting", + "media casting" + ], + "repository": "https://github.com/plex/plex", + "image": "https://hub.docker.com/r/linuxserver/plex", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Plex/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Plex/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Plex/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Plex/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Radarr", + "description": "Radarr is an automated movie download application, similar to CouchPotato. It helps you to manage your movie collection with features like metadata fetching, trailer linking, and integration with popular download clients. Radarr works across Windows, Linux, MacOS and has a mobile-friendly web interface. Start using Radarr now to automate and enhance your movie downloading and management process.", + "url": "", + "longDescription": "

Radarr is an independent fork of Sonarr reworked for automatically downloading movies via Usenet and BitTorrent. The project was inspired by other Usenet/BitTorrent movie downloaders such as CouchPotato.

Radarr provides a sleek, customizable interface to manage your movie collection, offering features like trailer linking, metadata fetching, and more. The software integrates with popular download clients and can automate your movie download process.

Radarr supports a variety of platforms including Windows, Linux, and MacOS, and also offers a mobile-friendly web interface. Setting up Radarr is straightforward. Get started today to streamline your movie downloading and management experience!

", + "tags": [ + "download", + "movies", + "torrent", + "usenet", + "automated", + "downloader", + "media", + "collection", + "usenet", + "bittorrent", + "windows", + "linux", + "macos", + "web interface", + "metadata", + "movie management", + "movie collection", + "radarr" + ], + "repository": "https://github.com/Radarr/Radarr", + "image": "https://hub.docker.com/r/linuxserver/radarr", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Radarr/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Radarr/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Radarr/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Radarr/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Readarr", + "description": "Readarr is an open-source, self-hosted PVR for managing and downloading ebooks. It offers features like adding favorite authors, automatic book searching, calendar integration, and importing existing libraries. Readarr supports integration with popular download clients and can send notifications. It can be run on Windows, Linux, MacOS, and Docker.", + "url": "", + "longDescription": "

Readarr is an open-source, self-hosted PVR (Personal Video Recorder) for managing and downloading ebooks. It's built off of the Radarr, Sonarr, and Lidarr platforms and brings the same powerful features to the world of ebooks.

Key features of Readarr include the ability to add your favorite authors, automatic book searching, calendar integration, and the ability to import existing libraries. It supports integration with popular download clients and can send notifications via a number of platforms.

Readarr is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", + "tags": [ + "download", + "ebooks", + "readarr", + "open-source", + "self-hosted", + "PVR", + "book management", + "download", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/Readarr/Readarr", + "image": "https://hub.docker.com/r/linuxserver/readarr", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Readarr/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Readarr/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Readarr/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Readarr/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Ryot", + "description": "A self hosted platform for tracking various facets of your life - media, fitness etc.", + "url": "", + "longDescription": "

Ryot is a self hosted platform for tracking various facets of your life - media, fitness etc. Imagine you have a special notebook where you can write down all the media you have consumed, like books you've read, shows you have watched, video games you have played or workouts you have done. Now, imagine that instead of a physical notebook, you have a special tool on your computer or phone that lets you keep track of all these digitally.

", + "tags": [ + "tracker", + "media", + "fitness", + "open-source", + "collection", + "docker", + "windows", + "linux", + "macos", + "web interface", + "metadata", + "episode tracking", + "movie tracking", + "audiobook tracking", + "reading tracking", + "fitness tracking", + "integrations", + "ryot" + ], + "repository": "https://github.com/IgnisDa/ryot", + "image": "https://ghcr.io/ignisda/ryot", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Ryot/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Ryot/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Ryot/screenshots/3.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Ryot/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Ryot/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Sonarr", + "description": "Sonarr is an automated TV show manager that can search, download, and manage your TV series. It offers features like automatic quality upgrades, episode tracking, and metadata fetching. Sonarr works across various platforms including Windows, Linux, MacOS, and has a mobile-friendly web interface. Start using Sonarr now to automate your TV show management process.", + "url": "", + "longDescription": "

Sonarr is a multi-platform app to search, download, and manage TV shows. It automates the process of searching for new episodes, and can automatically download these files with your preferred download software.

Sonarr offers features such as automatic quality upgrades, series and episode tracking, and metadata fetching to enrich your media library. The interface is user-friendly and mobile-responsive, ensuring you can manage your TV shows easily on any device.

Available for Windows, Linux, and MacOS, Sonarr makes the TV show management process easy and efficient. Get started with Sonarr today and transform your media management experience!

", + "tags": [ + "download", + "tv shows", + "torrent", + "usenet", + "automated", + "manager", + "media", + "collection", + "windows", + "linux", + "macos", + "web interface", + "metadata", + "episode tracking", + "quality upgrades", + "sonarr" + ], + "repository": "https://github.com/Sonarr/Sonarr", + "image": "https://hub.docker.com/r/linuxserver/sonarr", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Sonarr/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Sonarr/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Sonarr/screenshots/3.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Sonarr/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Sonarr/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Tandoor", + "description": "Tandoor is a recipe manager that allows you to manage your ever growing collection of digital recipes.", + "url": "", + "longDescription": "

Tandoor Recipes is the self hosted recipe manager with meal planning, shopping lists and cookbook collections.

The days of storing recipes on paper cards is in the past and what better way to preserve older recipes that were handed down then to log them into a digital, self hosted recipe manager where you can access them anywhere?

Tandoor Recipes is much more than a digital recipe reference archive, it's a complete meal planning power house.

", + "tags": [ + "recipes", + "meals", + "shopping", + "planning", + "cookbook", + "docker", + "pwa" + ], + "repository": "https://github.com/TandoorRecipes/recipes", + "image": "https://hub.docker.com/r/vabene1111/recipes", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Tandoor/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Tandoor/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Tandoor/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Tandoor/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Transmission", + "description": "Transmission is an open-source, cross-platform BitTorrent client. It is widely praised for its minimal resource usage, ease-of-use, and performance. Transmission provides features like built-in encryption, webseed support, peer exchange, automatic port mapping, and individual torrent speed limit settings. It supports Windows, Linux, MacOS, and also offers a web interface for remote control.", + "url": "", + "longDescription": "

Transmission is a cross-platform BitTorrent client that is open-source, volunteer-based, and free from advertisements. It is highly regarded for its low resource usage, simplicity, and performance.

With its intuitive interface, Transmission allows users to quickly and easily download and share files via the BitTorrent protocol. Its standout features include built-in encryption, webseed support, peer exchange, automatic port mapping, and the ability to set speed limits for individual torrents.

Transmission is available for a variety of platforms including Windows, Linux, and MacOS. It also provides a web interface for remote control, making it a popular choice among users looking for a lightweight, reliable BitTorrent client.

", + "tags": [ + "download", + "torrent", + "bittorrent", + "downloader", + "open-source", + "cross-platform", + "file sharing", + "peer-to-peer", + "p2p", + "transmission", + "windows", + "linux", + "macos", + "web interface" + ], + "repository": "https://github.com/transmission/transmission", + "image": "https://hub.docker.com/r/linuxserver/transmission", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Transmission/screenshots/1.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Transmission/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Transmission/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Unmanic", + "description": "Unmanic is a simple tool for optimising your file library. You can use it to convert your files into a single, uniform format, manage file movements based on timestamps, or execute custom commands against a file based on its file size.", + "url": "", + "longDescription": "

Unmanic is a simple tool for optimising your file library. You can use it to convert your files into a single, uniform format, manage file movements based on timestamps, or execute custom commands against a file based on its file size.

Simply configure Unmanic pointing it at your library and let it automatically manage that library for you.

Unmanic provides you with the following main functions:

", + "tags": [ + "media", + "server", + "tv", + "videos", + "web", + "browser", + "media browser", + "media server", + "media streaming", + "media player", + "media center", + "media management", + "media organizer", + "media collection", + "media library", + "media manager" + ], + "repository": "https://github.com/Unmanic/unmanic", + "image": "https://hub.docker.com/r/josh5/unmanic", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Unmanic/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Unmanic/screenshots/2.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Unmanic/screenshots/3.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Unmanic/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Unmanic/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm7", + "arm64" + ] + }, + { + "name": "Uptime Kuma", + "description": "Uptime Kuma is an open-source, self-hosted monitoring tool for tracking the uptime of online services. It offers status checks for various services, detailed statistics with charts, and multiple notification methods. Uptime Kuma is compatible with Windows, Linux, MacOS, and Docker.", + "url": "", + "longDescription": "

Uptime Kuma is an open-source, self-hosted monitoring tool that allows users to monitor their online services and get alerts when they go down or become unresponsive. This robust yet user-friendly tool is designed to help you keep track of your services' uptime.

Key features of Uptime Kuma include status checking for various services including HTTP(s), TCP, and ICMP, detailed statistics with charts, and multiple notification methods (like email, Slack, Telegram, etc.). Its clean, intuitive user interface makes setup and management of monitored services easy.

Uptime Kuma is compatible with various platforms, including Windows, Linux, MacOS, and it supports Docker, making it a highly versatile tool for various environments.

", + "tags": [ + "technical", + "administration", + "server", + "open-source", + "self-hosted", + "monitoring", + "uptime", + "service status", + "notifications", + "windows", + "linux", + "macos", + "docker" + ], + "repository": "https://github.com/louislam/uptime-kuma", + "image": "https://hub.docker.com/r/louislam/uptime-kuma", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/UptimeKuma/screenshots/1.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/UptimeKuma/screenshots/2.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/UptimeKuma/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/UptimeKuma/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Van_DAM", + "description": "A self-hosted digital asset manager for 3d print files", + "url": "", + "longDescription": "

VanDAM is a Digital Asset Manager (DAM), specifically designed for 3D print files. Create a library pointing at your files on disk, and it will scan for models and parts. It assumes that any folders containing STL or OBJ files are models, and the files within them are parts. You can then view the files easily through your browser!

", + "tags": [ + "3d models", + "3d printing" + ], + "repository": "https://github.com/Floppy/van_dam", + "image": "ghcr.io/floppy/van_dam", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Van_DAM/screenshots/1.jpg", + "https://azukaar.github.io/cosmos-servapps-official/servapps/Van_DAM/screenshots/2.jpg" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Van_DAM/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Van_DAM/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "Vaultwarden", + "description": "Vaultwarden is an open-source, self-hosted password management server compatible with Bitwarden apps. Written in Rust, it provides a secure way to store and synchronize sensitive data across devices with lightweight and low resource usage. Vaultwarden supports various platforms, including Linux, Windows, MacOS, and Docker.", + "url": "", + "longDescription": "

Vaultwarden is an open-source password management server that is compatible with Bitwarden apps. It provides a secure and free self-hosted solution to store and synchronize sensitive data across multiple devices, with the ability to share data across organizations, users, and teams.

Written in Rust, Vaultwarden is designed for lightweight and low resource usage. It allows you to store all kinds of sensitive information, including passwords, credit card details, and secure notes, which can be accessed through Bitwarden's web, mobile, or browser extension apps.

Vaultwarden supports various platforms, including Linux, Windows, MacOS, and can be deployed easily using Docker.

", + "tags": [ + "productivity", + "password-manager", + "password manager", + "bitwarden", + "rust", + "sensitive data", + "synchronization", + "linux", + "windows", + "macos", + "docker" + ], + "repository": "https://github.com/dani-garcia/vaultwarden", + "image": "https://hub.docker.com/r/vaultwarden/server", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Vaultwarden/screenshots/1.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Vaultwarden/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Vaultwarden/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "WordPress", + "description": "WordPress is a free, open-source content management system based on PHP and MySQL. Known for its flexibility and ease-of-use, it supports a range of website types with thousands of plugins and themes. WordPress features a robust administrative dashboard for website creation, modification, and management. It is widely supported across various hosting platforms.", + "url": "", + "longDescription": "

WordPress is a free and open-source content management system (CMS) based on PHP and MySQL. It is one of the most popular website management or blogging system in use on the Web, supporting more than 60 million websites.

WordPress allows users to create and edit websites through a central administrative dashboard, which includes a text editor for modifying content, menus and various design elements. It offers thousands of themes and plugins that can enhance functionality and customization options, making it suitable for a variety of website types, from personal blogs to online stores.

With its vast community, WordPress users have access to a plethora of resources, tutorials, and guides. Start your website journey with WordPress today!

", + "tags": [ + "blogging", + "cms", + "website management", + "php", + "mysql", + "themes", + "plugins", + "self-hosted", + "wordpress" + ], + "repository": "https://github.com/WordPress/WordPress", + "image": "https://hub.docker.com/_/wordpress", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/Wordpress/screenshots/1.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/Wordpress/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/Wordpress/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + }, + { + "name": "ntfy", + "description": "Send push notifications to your phone or desktop using PUT/POST.", + "url": "", + "longDescription": "

ntfy (pronounced \"notify\") is a simple HTTP-based pub-sub notification service. With ntfy, you can send notifications to your phone or desktop via scripts from any computer, without having to sign up or pay any fees.

", + "tags": [ + "notifications", + "rest api", + "curl", + "push notifications" + ], + "repository": "https://github.com/binwiederhier/ntfy", + "image": "https://hub.docker.com/r/binwiederhier/ntfy", + "screenshots": [ + "https://azukaar.github.io/cosmos-servapps-official/servapps/ntfy/screenshots/1.png", + "https://azukaar.github.io/cosmos-servapps-official/servapps/ntfy/screenshots/2.png" + ], + "icon": "https://azukaar.github.io/cosmos-servapps-official/servapps/ntfy/icon.png", + "compose": "https://azukaar.github.io/cosmos-servapps-official/servapps/ntfy/cosmos-compose.json", + "supported_architectures": [ + "amd64", + "arm64" + ] + } + ] + } + }, + "status": "OK" + }); }); } diff --git a/client/src/assets/images/icons/constellation.png b/client/src/assets/images/icons/constellation.png new file mode 100644 index 0000000..d507a44 Binary files /dev/null and b/client/src/assets/images/icons/constellation.png differ diff --git a/client/src/components/apiModal.jsx b/client/src/components/apiModal.jsx new file mode 100644 index 0000000..ceba699 --- /dev/null +++ b/client/src/components/apiModal.jsx @@ -0,0 +1,94 @@ +// material-ui +import { LoadingButton } from '@mui/lab'; +import { Button } from '@mui/material'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; +import * as React from 'react'; +import { useEffect, useState } from 'react'; + +const preStyle = { + backgroundColor: '#000', + color: '#fff', + padding: '10px', + borderRadius: '5px', + overflow: 'auto', + maxHeight: '500px', + maxWidth: '100%', + width: '100%', + margin: '0', + position: 'relative', + fontSize: '12px', + fontFamily: 'monospace', + whiteSpace: 'pre-wrap', + wordWrap: 'break-word', + wordBreak: 'break-all', + lineHeight: '1.5', + boxShadow: '0 0 10px rgba(0,0,0,0.5)', + border: '1px solid rgba(255,255,255,0.1)', + boxSizing: 'border-box', + marginBottom: '10px', + marginTop: '10px', + marginLeft: '0', + marginRight: '0', + display: 'block', + textAlign: 'left', + verticalAlign: 'baseline', + opacity: '1', +} + +const ApiModal = ({ callback, label }) => { + const [openModal, setOpenModal] = useState(false); + const [content, setContent] = useState(""); + const [loading, setLoading] = useState(true); + + const getContent = async () => { + setLoading(true); + let content = await callback(); + setContent(content.data); + setLoading(false); + }; + + useEffect(() => { + if (openModal) + getContent(); + }, [openModal]); + + return <> + setOpenModal(false)}> + Refresh Page + + +
+                  {content}
+                
+
+
+ + { + getContent(); + }}>Refresh + + +
+ + + +}; + +export default ApiModal; diff --git a/client/src/components/confirmModal.jsx b/client/src/components/confirmModal.jsx new file mode 100644 index 0000000..81bf673 --- /dev/null +++ b/client/src/components/confirmModal.jsx @@ -0,0 +1,48 @@ +// material-ui +import { LoadingButton } from '@mui/lab'; +import { Button } from '@mui/material'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; +import * as React from 'react'; +import { useEffect, useState } from 'react'; + +const ConfirmModal = ({ callback, label, content }) => { + const [openModal, setOpenModal] = useState(false); + + return <> + setOpenModal(false)}> + Are you sure? + + + {content} + + + + + { + callback(); + setOpenModal(false); + }}>Confirm + + + + + +}; + +export default ConfirmModal; diff --git a/client/src/components/fileUpload.jsx b/client/src/components/fileUpload.jsx index a7ba9fc..a541984 100644 --- a/client/src/components/fileUpload.jsx +++ b/client/src/components/fileUpload.jsx @@ -2,7 +2,7 @@ import React from 'react'; import { Button } from '@mui/material'; import { UploadOutlined } from '@ant-design/icons'; -export default function UploadButtons({OnChange, accept, label}) { +export default function UploadButtons({OnChange, accept, label, variant, fullWidth, size}) { return (
diff --git a/client/src/index.css b/client/src/index.css index 3c6d9ab..39e1eae 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -123,8 +123,9 @@ align-items: center; } -.loading-image { - background: url('/assets/images/icons/cosmos_gray.png') no-repeat center center; +.loading-image:empty { + /* background: url('assets/images/icons/cosmos_gray.png') no-repeat center center; + background-size: contain; */ } .raw-table table { diff --git a/client/src/layout/MainLayout/Drawer/DrawerContent/Navigation/NavGroup.jsx b/client/src/layout/MainLayout/Drawer/DrawerContent/Navigation/NavGroup.jsx index 9c001af..77a1365 100644 --- a/client/src/layout/MainLayout/Drawer/DrawerContent/Navigation/NavGroup.jsx +++ b/client/src/layout/MainLayout/Drawer/DrawerContent/Navigation/NavGroup.jsx @@ -47,7 +47,7 @@ const NavGroup = ({ item }) => { } sx={{ mb: drawerOpen ? 1.5 : 0, py: 0, zIndex: 0 }} > - {navCollapse} + {navCollapse} ); }; diff --git a/client/src/layout/MainLayout/Drawer/DrawerContent/Navigation/NavItem.jsx b/client/src/layout/MainLayout/Drawer/DrawerContent/Navigation/NavItem.jsx index 77a3df0..162d325 100644 --- a/client/src/layout/MainLayout/Drawer/DrawerContent/Navigation/NavItem.jsx +++ b/client/src/layout/MainLayout/Drawer/DrawerContent/Navigation/NavItem.jsx @@ -9,6 +9,7 @@ import { Avatar, Chip, ListItemButton, ListItemIcon, ListItemText, Typography } // project import import { activeItem } from '../../../../../store/reducers/menu'; +import { useClientInfos } from '../../../../../utils/hooks'; // ==============================|| NAVIGATION - LIST ITEM ||============================== // @@ -17,6 +18,12 @@ const NavItem = ({ item, level }) => { const dispatch = useDispatch(); const menu = useSelector((state) => state.menu); const { drawerOpen, openItem } = menu; + const {role} = useClientInfos(); + const isAdmin = role === "2"; + + if (item.adminOnly && !isAdmin) { + return null; + } let itemTarget = '_self'; if (item.target) { @@ -54,6 +61,16 @@ const NavItem = ({ item, level }) => { const textColor = 'text.primary'; const iconSelectedColor = 'primary.main'; + // SET BETA (TODO REMOVE) + if(item.title === "Constellation") + item.title = <>{item.title} Beta; + return ( , + + }, { id: 'users', title: 'Users', type: 'item', url: '/cosmos-ui/config-users', icon: icons.ProfileOutlined, + adminOnly: true }, { id: 'openid', @@ -42,6 +52,7 @@ const pages = { type: 'item', url: '/cosmos-ui/openid-manage', icon: PicLeftOutlined, + adminOnly: true }, { id: 'config', diff --git a/client/src/pages/authentication/Logoff.jsx b/client/src/pages/authentication/Logoff.jsx index 635efc0..3e7924f 100644 --- a/client/src/pages/authentication/Logoff.jsx +++ b/client/src/pages/authentication/Logoff.jsx @@ -9,7 +9,7 @@ import AuthWrapper from './AuthWrapper'; import { useEffect } from 'react'; import * as API from '../../api'; -import { redirectTo } from '../../utils/indexs'; +import { redirectTo, redirectToLocal } from '../../utils/indexs'; // ================================|| REGISTER ||================================ // diff --git a/client/src/pages/config/routes/routeman.jsx b/client/src/pages/config/routes/routeman.jsx index e3f1162..48037f4 100644 --- a/client/src/pages/config/routes/routeman.jsx +++ b/client/src/pages/config/routes/routeman.jsx @@ -11,7 +11,7 @@ import { FormHelperText, } from '@mui/material'; import RestartModal from '../users/restart'; -import { CosmosCheckbox, CosmosFormDivider, CosmosInputText, CosmosSelect } from '../users/formShortcuts'; +import { CosmosCheckbox, CosmosCollapse, CosmosFormDivider, CosmosInputText, CosmosSelect } from '../users/formShortcuts'; import { CosmosContainerPicker } from '../users/containerPicker'; import { snackit } from '../../../api/wrap'; import { ValidateRouteSchema, sanitizeRoute } from '../../../utils/routes'; @@ -72,12 +72,20 @@ const RouteManagement = ({ routeConfig, routeNames, config, TargetContainer, noC StripPathPrefix: routeConfig.StripPathPrefix, AuthEnabled: routeConfig.AuthEnabled, _SmartShield_Enabled: (routeConfig.SmartShield ? routeConfig.SmartShield.Enabled : false), + RestrictToConstellation: routeConfig.RestrictToConstellation, + OverwriteHostHeader: routeConfig.OverwriteHostHeader, + WhitelistInboundIPs: routeConfig.WhitelistInboundIPs && routeConfig.WhitelistInboundIPs.join(', '), }} validationSchema={ValidateRouteSchema} onSubmit={async (values, { setErrors, setStatus, setSubmitting }) => { if(!submitButton) { return false; } else { + let commaSepIps = values.WhitelistInboundIPs; + if(commaSepIps) { + values.WhitelistInboundIPs = commaSepIps.split(',').map((ip) => ip.trim()); + } + let fullValues = { ...routeConfig, ...values, @@ -256,6 +264,37 @@ const RouteManagement = ({ routeConfig, routeNames, config, TargetContainer, noC label="Smart Shield Protection" formik={formik} /> + + + + + + These settings are for advanced users only. Please do not change these unless you know what you are doing. + + + + This setting will filter out all requests that do not come from the specified IPs. + This requires your setup to report the true IP of the client. By default it will, but some exotic setup (like installing docker/cosmos on Windows, or behind Cloudlfare) + will prevent Cosmos from knowing what is the client's real IP. If you used "Restrict to Constellation" above, Constellation IPs will always be allowed regardless of this setting. + + + + + {submitButton && - + }}>Restart Server} {config && <> @@ -186,7 +189,7 @@ const ConfigManagement = () => { {(formik) => (
- + {isAdmin && {formik.errors.submit && ( {formik.errors.submit} @@ -205,7 +208,13 @@ const ConfigManagement = () => { {saveLabel} - + } + + {!isAdmin &&
+ As you are not an admin, you can't edit the configuration. + This page is only here for visibility. + +
} @@ -331,6 +340,29 @@ const ConfigManagement = () => { formik.setFieldValue('PrimaryColor', colorRGB); SetPrimaryColor(colorRGB); }} + colors={[ + '#ab47bc', + '#4527a0', + '#FF6900', + '#FCB900', + '#7BDCB5', + '#00D084', + '#8ED1FC', + '#0693E3', + '#ABB8C3', + '#EB144C', + '#F78DA7', + '#9900EF', + '#FF0000', + '#FFC0CB', + '#20B2AA', + '#FFFF00', + '#8A2BE2', + '#A52A2A', + '#5F9EA0', + '#7FFF00', + '#D2691E' + ]} />
@@ -346,6 +378,29 @@ const ConfigManagement = () => { formik.setFieldValue('SecondaryColor', colorRGB); SetSecondaryColor(colorRGB); }} + colors={[ + '#ab47bc', + '#4527a0', + '#FF6900', + '#FCB900', + '#7BDCB5', + '#00D084', + '#8ED1FC', + '#0693E3', + '#ABB8C3', + '#EB144C', + '#F78DA7', + '#9900EF', + '#FF0000', + '#FFC0CB', + '#20B2AA', + '#FFFF00', + '#8A2BE2', + '#A52A2A', + '#5F9EA0', + '#7FFF00', + '#D2691E' + ]} /> @@ -627,7 +682,7 @@ const ConfigManagement = () => { - + {isAdmin && {formik.errors.submit && ( {formik.errors.submit} @@ -646,7 +701,7 @@ const ConfigManagement = () => { {saveLabel} - + }
)} diff --git a/client/src/pages/config/users/formShortcuts.jsx b/client/src/pages/config/users/formShortcuts.jsx index 78d9c43..4419ebb 100644 --- a/client/src/pages/config/users/formShortcuts.jsx +++ b/client/src/pages/config/users/formShortcuts.jsx @@ -27,26 +27,33 @@ import { strengthColor, strengthIndicator } from '../../../utils/password-streng import { EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons'; -export const CosmosInputText = ({ name, style, multiline, type, placeholder, onChange, label, formik }) => { +export const CosmosInputText = ({ name, style, value, errors, multiline, type, placeholder, onChange, label, formik }) => { return - {label} + {label && {label}} { + return formik && formik.handleBlur(...ar); + }} onChange={(...ar) => { onChange && onChange(...ar); - return formik.handleChange(...ar); + return formik && formik.handleChange(...ar); }} placeholder={placeholder} fullWidth - error={Boolean(formik.touched[name] && formik.errors[name])} + error={Boolean(formik && formik.touched[name] && formik.errors[name])} /> - {formik.touched[name] && formik.errors[name] && ( + {formik && formik.touched[name] && formik.errors[name] && ( + + {formik.errors[name]} + + )} + {errors && ( {formik.errors[name]} @@ -206,7 +213,7 @@ export const CosmosCollapse = ({ children, title }) => { export function CosmosFormDivider({title}) { return - + {title && } } diff --git a/client/src/pages/constellation/addDevice.jsx b/client/src/pages/constellation/addDevice.jsx new file mode 100644 index 0000000..7ee3c5f --- /dev/null +++ b/client/src/pages/constellation/addDevice.jsx @@ -0,0 +1,302 @@ +// material-ui +import { Alert, Button, InputLabel, OutlinedInput, Stack, TextField } from '@mui/material'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; +import * as React from 'react'; +import { useState } from 'react'; +import ResponsiveButton from '../../components/responseiveButton'; +import { PlusCircleFilled } from '@ant-design/icons'; +import { Formik } from 'formik'; +import * as yup from 'yup'; +import * as API from '../../api'; +import { CosmosCheckbox, CosmosFormDivider, CosmosInputText, CosmosSelect } from '../config/users/formShortcuts'; +import { DownloadFile } from '../../api/downloadButton'; +import QRCode from 'qrcode'; +import { useClientInfos } from '../../utils/hooks'; + +const getDocker = (data, isCompose) => { + let lighthouses = ''; + + for (let i = 0; i < data.LighthousesList.length; i++) { + const l = data.LighthousesList[i]; + lighthouses += l.publicHostname + ";" + l.ip + ":" + l.port + ";" + l.isRelay + ","; + } + + let containerName = "cosmos-constellation-lighthouse"; + let imageName = "cosmos-constellation-lighthouse:latest"; + + let volPath = "/var/lib/cosmos-constellation"; + + if (isCompose) { + return ` +version: "3.8" +services: + ${containerName}: + image: ${imageName} + container_name: ${containerName} + restart: unless-stopped + network_mode: bridge + ports: + - "${data.Port}:4242" + volumes: + - ${volPath}:/config + environment: + - CA=${JSON.stringify(data.CA)} + - CERT=${JSON.stringify(data.PrivateKey)} + - KEY=${JSON.stringify(data.PublicKey)} + - LIGHTHOUSES=${lighthouses} + - PUBLIC_HOSTNAME=${data.PublicHostname} + - IS_RELAY=${data.IsRelay} + - IP=${data.IP} +`; + } else { + return ` +docker run -d \\ + --name ${containerName} \\ + --restart unless-stopped \\ + --network bridge \\ + -v ${volPath}:/config \\ + -e CA=${JSON.stringify(data.CA)} \\ + -e CERT=${JSON.stringify(data.PrivateKey)} \\ + -e KEY=${JSON.stringify(data.PublicKey)} \\ + -e LIGHTHOUSES=${lighthouses} \\ + -e PUBLIC_HOSTNAME=${data.PublicHostname} \\ + -e IS_RELAY=${data.IsRelay} \\ + -e IP=${data.IP} \\ + -p ${data.Port}:4242 \\ + ${imageName} +`; + } + +} + + +const AddDeviceModal = ({ users, config, refreshConfig, devices }) => { + const [openModal, setOpenModal] = useState(false); + const [isDone, setIsDone] = useState(null); + const canvasRef = React.useRef(null); + const {role, nickname} = useClientInfos(); + const isAdmin = role === "2"; + + let firstIP = "192.168.201.2/24"; + if (devices && devices.length > 0) { + const isIpFree = (ip) => { + return devices.filter((d) => d.ip === ip).length === 0; + } + let i = 1; + let j = 201; + while (!isIpFree(firstIP)) { + i++; + if (i > 254) { + i = 0; + j++; + } + firstIP = "192.168." + j + "." + i + "/24"; + } + } + + const renderCanvas = (data) => { + if (!canvasRef.current) return setTimeout(() => { + renderCanvas(data); + }, 500); + + QRCode.toCanvas(canvasRef.current, JSON.stringify(data), + { + width: 600, + color: { + dark: "#000", + light: '#fff' + } + }, function (error) { + if (error) console.error(error) + }) + } + + return <> + setOpenModal(false)}> + { + if(values.isLighthouse) values.nickname = null; + + return API.constellation.addDevice(values).then(({data}) => { + setIsDone(data); + refreshConfig(); + renderCanvas(data.Config); + }).catch((err) => { + setErrors(err.response.data); + }); + }} + > + {(formik) => ( +
+ Add Device + + {isDone ? + +

+ Device added successfully! + Download scan the QR Code from the Cosmos app or download the relevant + files to your device along side the config and network certificate to + connect: +

+ + + {/* {isDone.isLighthouse ? <> + + + + + : <> */} + +
+ +
+ {/* } */} + + + +
+
+
: + +

Add a Device to the constellation using either the Cosmos or Nebula client

+
+ + + {!formik.values.isLighthouse && + (isAdmin ? { + return [u.nickname, u.nickname] + }) + } + /> : <> + Owner + + )} + + + + + + {/* */} + + + {formik.values.isLighthouse && <> + + + + + + } +
+ {formik.errors && formik.errors.length > 0 && + {formik.errors.map((err) => { + return
{err}
+ })}
+
} +
+
+
+
+
} + + + + {!isDone && } + +
+ + )} +
+
+ + { + setIsDone(null); + setOpenModal(true); + }} + variant={ + "contained" + } + startIcon={} + > + Add Device + + ; +}; + +export default AddDeviceModal; diff --git a/client/src/pages/constellation/dns.jsx b/client/src/pages/constellation/dns.jsx new file mode 100644 index 0000000..35f75fb --- /dev/null +++ b/client/src/pages/constellation/dns.jsx @@ -0,0 +1,174 @@ +import React from "react"; +import { useEffect, useState } from "react"; +import * as API from "../../api"; +import AddDeviceModal from "./addDevice"; +import PrettyTableView from "../../components/tableView/prettyTableView"; +import { DeleteButton } from "../../components/delete"; +import { CloudOutlined, CloudServerOutlined, CompassOutlined, DesktopOutlined, LaptopOutlined, MobileOutlined, TabletOutlined } from "@ant-design/icons"; +import IsLoggedIn from "../../isLoggedIn"; +import { Alert, Button, CircularProgress, InputLabel, Stack } from "@mui/material"; +import { CosmosCheckbox, CosmosFormDivider, CosmosInputText } from "../config/users/formShortcuts"; +import MainCard from "../../components/MainCard"; +import { Formik } from "formik"; +import { LoadingButton } from "@mui/lab"; +import ApiModal from "../../components/apiModal"; +import { isDomain } from "../../utils/indexs"; +import ConfirmModal from "../../components/confirmModal"; +import UploadButtons from "../../components/fileUpload"; + +export const ConstellationDNS = () => { + const [isAdmin, setIsAdmin] = useState(false); + const [config, setConfig] = useState(null); + + const refreshConfig = async () => { + let configAsync = await API.config.get(); + setConfig(configAsync.data); + setIsAdmin(configAsync.isAdmin); + }; + + useEffect(() => { + refreshConfig(); + }, []); + + return <> + {(config) ? <> + +
+ + + + { + let newConfig = { ...config }; + newConfig.ConstellationConfig.DNSFallback = values.Fallback; + newConfig.ConstellationConfig.DNSBlockBlacklist = values.DNSBlockBlacklist; + newConfig.ConstellationConfig.DNSAdditionalBlocklists = values.DNSAdditionalBlocklists; + newConfig.ConstellationConfig.CustomDNSEntries = values.CustomDNSEntries; + + return API.config.set(newConfig); + }} + > + {(formik) => ( +
+ + This is a DNS that runs inside your Constellation network. It automatically + rewrites your domains DNS entries to be local to your network, and also allows you to do things like block ads + and trackers on all devices connected to your network. You can also add custom DNS entries to resolve to specific + IP addresses. This DNS server is only accessible from inside your network. + + + + + + + + When changing your DNS records, always use private mode on your browser and allow some times for various caches to expire. + + DNS Blocklist URLs + {formik.values.DNSAdditionalBlocklists && formik.values.DNSAdditionalBlocklists.map((item, index) => ( + + { + formik.setFieldValue("DNSAdditionalBlocklists", [...formik.values.DNSAdditionalBlocklists.slice(0, index), ...formik.values.DNSAdditionalBlocklists.slice(index + 1)]); + }} /> +
+ { + formik.setFieldValue("DNSAdditionalBlocklists", [...formik.values.DNSAdditionalBlocklists.slice(0, index), e.target.value, ...formik.values.DNSAdditionalBlocklists.slice(index + 1)]); + }} + /> +
+
+ ))} + + + + + + + + DNS Custom Entries + {formik.values.CustomDNSEntries && formik.values.CustomDNSEntries.map((item, index) => ( + + { + formik.setFieldValue("CustomDNSEntries", [...formik.values.CustomDNSEntries.slice(0, index), ...formik.values.CustomDNSEntries.slice(index + 1)]); + }} /> +
+ { + const updatedCustomDNSEntries = [...formik.values.CustomDNSEntries]; + updatedCustomDNSEntries[index].Key = e.target.value; + formik.setFieldValue("CustomDNSEntries", updatedCustomDNSEntries); + }} + /> +
+
+ { + const updatedCustomDNSEntries = [...formik.values.CustomDNSEntries]; + updatedCustomDNSEntries[index].Value = e.target.value; + formik.setFieldValue("CustomDNSEntries", updatedCustomDNSEntries); + }} + /> +
+
+ ))} + + + + + + + Save + +
+
+ )} +
+
+
+
+
+ :
+ +
} + +}; \ No newline at end of file diff --git a/client/src/pages/constellation/index.jsx b/client/src/pages/constellation/index.jsx new file mode 100644 index 0000000..93d6e83 --- /dev/null +++ b/client/src/pages/constellation/index.jsx @@ -0,0 +1,57 @@ +import * as React from 'react'; +import MainCard from '../../components/MainCard'; +import { Alert, Chip, Divider, Stack, useMediaQuery } from '@mui/material'; +import HostChip from '../../components/hostChip'; +import { RouteMode, RouteSecurity } from '../../components/routeComponents'; +import { getFaviconURL } from '../../utils/routes'; +import * as API from '../../api'; +import { CheckOutlined, ClockCircleOutlined, DashboardOutlined, DeleteOutlined, DownOutlined, LockOutlined, UpOutlined } from "@ant-design/icons"; +import IsLoggedIn from '../../isLoggedIn'; +import PrettyTabbedView from '../../components/tabbedView/tabbedView'; +import { useClientInfos } from '../../utils/hooks'; + +import { ConstellationVPN } from './vpn'; +import { ConstellationDNS } from './dns'; + +const ConstellationIndex = () => { + const {role} = useClientInfos(); + const isAdmin = role === "2"; + + return isAdmin ?
+ + + , + path: 'vpn' + }, + { + title: 'DNS', + children: , + path: 'dns' + }, + { + title: 'Firewall', + children:
+ + Coming soon. This feature will allow you to open and close ports individually + on each device and decide who can access them. + +
, + }, + { + title: 'Unsafe Routes', + children:
+ + Coming soon. This feature will allow you to tunnel your traffic through + your devices to things outside of your constellation. + +
, + } + ]}/> + +
: ; +} + +export default ConstellationIndex; \ No newline at end of file diff --git a/client/src/pages/constellation/vpn.jsx b/client/src/pages/constellation/vpn.jsx new file mode 100644 index 0000000..232aab6 --- /dev/null +++ b/client/src/pages/constellation/vpn.jsx @@ -0,0 +1,219 @@ +import React from "react"; +import { useEffect, useState } from "react"; +import * as API from "../../api"; +import AddDeviceModal from "./addDevice"; +import PrettyTableView from "../../components/tableView/prettyTableView"; +import { DeleteButton } from "../../components/delete"; +import { CloudOutlined, CloudServerOutlined, CompassOutlined, DesktopOutlined, LaptopOutlined, MobileOutlined, TabletOutlined } from "@ant-design/icons"; +import IsLoggedIn from "../../isLoggedIn"; +import { Alert, Button, CircularProgress, Stack } from "@mui/material"; +import { CosmosCheckbox, CosmosFormDivider, CosmosInputText } from "../config/users/formShortcuts"; +import MainCard from "../../components/MainCard"; +import { Formik } from "formik"; +import { LoadingButton } from "@mui/lab"; +import ApiModal from "../../components/apiModal"; +import { isDomain } from "../../utils/indexs"; +import ConfirmModal from "../../components/confirmModal"; +import UploadButtons from "../../components/fileUpload"; +import { useClientInfos } from "../../utils/hooks"; + +const getDefaultConstellationHostname = (config) => { + // if domain is set, use it + if(isDomain(config.HTTPConfig.Hostname)) { + return "vpn." + config.HTTPConfig.Hostname; + } else { + return config.HTTPConfig.Hostname; + } +} + +export const ConstellationVPN = () => { + const [config, setConfig] = useState(null); + const [users, setUsers] = useState(null); + const [devices, setDevices] = useState(null); + const {role} = useClientInfos(); + const isAdmin = role === "2"; + + const refreshConfig = async () => { + let configAsync = await API.config.get(); + setConfig(configAsync.data); + setDevices((await API.constellation.list()).data || []); + if(isAdmin) + setUsers((await API.users.list()).data || []); + else + setUsers([]); + }; + + useEffect(() => { + refreshConfig(); + }, []); + + const getIcon = (r) => { + if (r.deviceName.toLowerCase().includes("mobile") || r.deviceName.toLowerCase().includes("phone")) { + return + } + else if (r.deviceName.toLowerCase().includes("laptop") || r.deviceName.toLowerCase().includes("computer")) { + return + } else if (r.deviceName.toLowerCase().includes("desktop")) { + return + } else if (r.deviceName.toLowerCase().includes("tablet")) { + return + } else if (r.deviceName.toLowerCase().includes("lighthouse") || r.deviceName.toLowerCase().includes("server")) { + return + } else { + return + } + } + + return <> + {(devices && config && users) ? <> + +
+ + Constellation is a VPN that runs inside your Cosmos network. It automatically + connects all your devices together, and allows you to access them from anywhere. + Please refer to the documentation for more information. + In order to connect, please use the Constellation App. + + + + {config.ConstellationConfig.Enabled && config.ConstellationConfig.SlaveMode && <> + + You are currently connected to an external constellation network. Use your main Cosmos server to manage your constellation network and devices. + + } + { + let newConfig = { ...config }; + newConfig.ConstellationConfig.Enabled = values.Enabled; + newConfig.ConstellationConfig.PrivateNode = values.PrivateNode; + newConfig.ConstellationConfig.NebulaConfig.Relay.AMRelay = values.IsRelay; + newConfig.ConstellationConfig.ConstellationHostname = values.ConstellationHostname; + setTimeout(() => { + refreshConfig(); + }, 1500); + return API.config.set(newConfig); + }} + > + {(formik) => ( +
+ + {formik.values.Enabled && + + + + { + await API.constellation.reset(); + refreshConfig(); + }} + /> + } + + {config.ConstellationConfig.Enabled && !config.ConstellationConfig.SlaveMode && <> + {formik.values.Enabled && <> + + + {!formik.values.PrivateNode && <> + This is your Constellation hostname, that you will use to connect. If you are using a domain name, this needs to be different from your server's hostname. Whatever the domain you choose, it is very important that you make sure there is a A entry in your domain DNS pointing to this server. If you change this value, you will need to reset your network and reconnect all the clients! + + } + } + } + + Save + + { + let file = e.target.files[0]; + await API.constellation.connect(file); + setTimeout(() => { + refreshConfig(); + }, 1000); + }} + /> + +
+ )} +
+
+
+
+ {config.ConstellationConfig.Enabled && !config.ConstellationConfig.SlaveMode && <> + + !d.blocked)} + getKey={(r) => r.deviceName} + buttons={[ + , + ]} + columns={[ + { + title: '', + field: getIcon, + }, + { + title: 'Device Name', + field: (r) => {r.deviceName}, + }, + { + title: 'Owner', + field: (r) => {r.nickname}, + }, + { + title: 'Type', + field: (r) => {r.isLighthouse ? "Lighthouse" : "Client"}, + }, + { + title: 'Constellation IP', + screenMin: 'md', + field: (r) => r.ip, + }, + { + title: '', + clickable: true, + field: (r) => { + return { + await API.constellation.block(r.nickname, r.deviceName, true); + refreshConfig(); + }}> + } + } + ]} + /> + } +
+ :
+ +
} + +}; \ No newline at end of file diff --git a/client/src/pages/home/index.jsx b/client/src/pages/home/index.jsx index e3cee33..5905e7f 100644 --- a/client/src/pages/home/index.jsx +++ b/client/src/pages/home/index.jsx @@ -12,6 +12,7 @@ import { getFullOrigin } from "../../utils/routes"; import IsLoggedIn from "../../isLoggedIn"; import { ServAppIcon } from "../../utils/servapp-icon"; import Chart from 'react-apexcharts'; +import { useClientInfos } from "../../utils/hooks"; export const HomeBackground = () => { @@ -87,6 +88,8 @@ const HomePage = () => { const theme = useTheme(); const isDark = theme.palette.mode === 'dark'; const isMd = useMediaQuery(theme.breakpoints.up('md')); + const {role} = useClientInfos(); + const isAdmin = role === "2"; const blockStyle = { margin: 0, @@ -112,9 +115,13 @@ const HomePage = () => { } const refreshConfig = () => { - API.docker.list().then((res) => { - setServApps(res.data); - }); + if(isAdmin) { + API.docker.list().then((res) => { + setServApps(res.data); + }); + } else { + setServApps([]); + } API.config.get().then((res) => { setConfig(res.data); }); @@ -213,47 +220,47 @@ const HomePage = () => { - {coStatus && !coStatus.database && ( + {isAdmin && coStatus && !coStatus.database && ( No Database is setup for Cosmos! User Management and Authentication will not work.
You can either setup the database, or disable user management in the configuration panel.
)} - {coStatus && coStatus.letsencrypt && ( + {isAdmin && coStatus && coStatus.letsencrypt && ( You have enabled Let's Encrypt for automatic HTTPS Certificate. You need to provide the configuration with an email address to use for Let's Encrypt in the configs. )} - {coStatus && coStatus.LetsEncryptErrors && coStatus.LetsEncryptErrors.length > 0 && ( + {isAdmin && coStatus && coStatus.LetsEncryptErrors && coStatus.LetsEncryptErrors.length > 0 && ( - There are errors with your Let's Encrypt configuration or one of your routes, please fix them as soon as possible.: + There are errors with your Let's Encrypt configuration or one of your routes, please fix them as soon as possible: {coStatus.LetsEncryptErrors.map((err) => { return
- {err}
})}
)} - {coStatus && coStatus.newVersionAvailable && ( + {isAdmin && coStatus && coStatus.newVersionAvailable && ( A new version of Cosmos is available! Please update to the latest version to get the latest features and bug fixes. )} - {coStatus && coStatus.needsRestart && ( + {isAdmin && coStatus && coStatus.needsRestart && ( You have made changes to the configuration that require a restart to take effect. Please restart Cosmos to apply the changes. )} - {coStatus && coStatus.domain && ( + {isAdmin && coStatus && coStatus.domain && ( You are using localhost or 0.0.0.0 as a hostname in the configuration. It is recommended that you use a domain name or an IP instead. )} - {coStatus && !coStatus.docker && ( + {isAdmin && coStatus && !coStatus.docker && ( Docker is not connected! Please check your docker connection.
Did you forget to add
-v /var/run/docker.sock:/var/run/docker.sock
to your docker run command?
diff --git a/client/src/pages/market/listing.jsx b/client/src/pages/market/listing.jsx index 6a8d6e7..f7587d9 100644 --- a/client/src/pages/market/listing.jsx +++ b/client/src/pages/market/listing.jsx @@ -12,6 +12,7 @@ import { Link as LinkMUI } from '@mui/material' import DockerComposeImport from '../servapps/containers/docker-compose'; import { AppstoreAddOutlined, SearchOutlined } from "@ant-design/icons"; import ResponsiveButton from "../../components/responseiveButton"; +import { useClientInfos } from "../../utils/hooks"; function Screenshots({ screenshots }) { return screenshots.length > 1 ? ( @@ -23,17 +24,17 @@ function Screenshots({ screenshots }) { : } -function Showcases({ showcase, isDark }) { +function Showcases({ showcase, isDark, isAdmin }) { return ( { - showcase.map((item, i) => ) + showcase.map((item, i) => ) } ) } -function ShowcasesItem({ isDark, item }) { +function ShowcasesItem({ isDark, item, isAdmin }) { return (

-
+ {isAdmin &&
-
+
} @@ -110,6 +111,8 @@ const MarketPage = () => { const isDark = theme.palette.mode === 'dark'; const { appName, appStore } = useParams(); const [search, setSearch] = useState(""); + const {role} = useClientInfos(); + const isAdmin = role === "2"; const backgroundStyle = isDark ? { backgroundColor: 'rgb(0,0,0)', @@ -178,7 +181,7 @@ const MarketPage = () => {
- +
@@ -202,9 +205,9 @@ const MarketPage = () => {
-
+ {isAdmin &&
-
+
}
} @@ -223,7 +226,7 @@ const MarketPage = () => { size={100} /> } - {showcase && showcase.length > 0 && } + {showcase && showcase.length > 0 && }
}, + { + path: '/cosmos-ui/constellation', + element: + }, { path: '/cosmos-ui/servapps', element: diff --git a/client/src/utils/hooks.js b/client/src/utils/hooks.js new file mode 100644 index 0000000..aa24f46 --- /dev/null +++ b/client/src/utils/hooks.js @@ -0,0 +1,29 @@ +import React from 'react'; +import { useCookies } from 'react-cookie'; +import { logout } from '../api/authentication'; + +function useClientInfos() { + const [cookies] = useCookies(['client-infos']); + + let clientInfos = null; + + try { + // Try to parse the cookie into a JavaScript object + clientInfos = cookies['client-infos'].split(','); + + return { + nickname: clientInfos[0], + role: clientInfos[1] + }; + } catch (error) { + console.error('Error parsing client-infos cookie:', error); + return { + nickname: "", + role: 2 + }; + } +} + +export { + useClientInfos +}; \ No newline at end of file diff --git a/client/src/utils/indexs.js b/client/src/utils/indexs.js index cf7a756..8caa9b5 100644 --- a/client/src/utils/indexs.js +++ b/client/src/utils/indexs.js @@ -1,3 +1,5 @@ +import { Button } from "@mui/material"; + export const randomString = (length) => { let text = ""; const possible = @@ -45,4 +47,4 @@ export const redirectToLocal = (url) => { throw new Error("URL must be local"); } window.location.href = url; -} \ No newline at end of file +} diff --git a/dockerfile b/dockerfile index ccbe859..e7949ce 100644 --- a/dockerfile +++ b/dockerfile @@ -29,7 +29,7 @@ WORKDIR /app COPY build/cosmos build/cosmos-arm64 ./ # Copy other resources -COPY build/cosmos_gray.png build/Logo.png build/GeoLite2-Country.mmdb build/meta.json ./ +COPY build/* ./ COPY static ./static # Run the respective binary based on the BINARY_NAME diff --git a/dockerfile.arm64 b/dockerfile.arm64 index 2a313e2..79b1f58 100644 --- a/dockerfile.arm64 +++ b/dockerfile.arm64 @@ -13,7 +13,8 @@ RUN apt-get update \ WORKDIR /app -COPY build/cosmos build/cosmos_gray.png build/Logo.png build/GeoLite2-Country.mmdb build/meta.json ./ + +COPY build/* ./ COPY static ./static CMD ["./cosmos"] diff --git a/go.mod b/go.mod index 4e40dd9..7c1de41 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/docker/docker v23.0.3+incompatible github.com/docker/go-connections v0.4.0 github.com/foomo/tlsconfig v0.0.0-20180418120404-b67861b076c9 - github.com/go-acme/lego/v4 v4.13.3 + github.com/go-acme/lego/v4 v4.14.2 github.com/go-chi/chi v4.0.2+incompatible github.com/go-chi/httprate v0.7.1 github.com/go-playground/validator/v10 v10.14.0 @@ -16,7 +16,9 @@ require ( github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/jasonlvhit/gocron v0.0.1 + github.com/miekg/dns v1.1.55 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f + github.com/natefinch/lumberjack v2.0.0+incompatible github.com/ory/fosite v0.44.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/pquerna/otp v1.4.0 @@ -27,6 +29,7 @@ require ( golang.org/x/crypto v0.10.0 golang.org/x/net v0.11.0 golang.org/x/sys v0.9.0 + gopkg.in/yaml.v2 v2.4.0 ) require ( @@ -57,7 +60,20 @@ require ( github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/andybalholm/cascadia v1.1.0 // indirect github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect - github.com/aws/aws-sdk-go v1.39.0 // indirect + github.com/aws/aws-sdk-go-v2 v1.19.0 // indirect + github.com/aws/aws-sdk-go-v2/config v1.18.28 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.27 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 // indirect + github.com/aws/aws-sdk-go-v2/service/lightsail v1.27.2 // indirect + github.com/aws/aws-sdk-go-v2/service/route53 v1.28.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 // indirect + github.com/aws/smithy-go v1.13.5 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -126,7 +142,6 @@ require ( github.com/magiconair/properties v1.8.4 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/goveralls v0.0.6 // indirect - github.com/miekg/dns v1.1.55 // indirect github.com/mimuret/golang-iij-dpf v0.9.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -137,6 +152,7 @@ require ( github.com/montanaflynn/stats v0.7.0 // indirect github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect github.com/nrdcg/auroradns v1.1.0 // indirect + github.com/nrdcg/bunny-go v0.0.0-20230728143221-c9dda82568d9 // indirect github.com/nrdcg/desec v0.7.0 // indirect github.com/nrdcg/dnspod-go v0.4.0 // indirect github.com/nrdcg/freemyip v0.2.0 // indirect @@ -153,7 +169,7 @@ require ( github.com/ory/viper v1.7.5 // indirect github.com/ory/x v0.0.214 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect - github.com/ovh/go-ovh v1.4.1 // indirect + github.com/ovh/go-ovh v1.4.2 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pborman/uuid v1.2.0 // indirect github.com/pelletier/go-toml v1.8.1 // indirect @@ -167,7 +183,6 @@ require ( github.com/sacloud/packages-go v0.0.9 // indirect github.com/scaleway/scaleway-sdk-go v1.0.0-beta.17 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect - github.com/simplesurance/bunny-go v0.0.0-20221115111006-e11d9dc91f04 // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect github.com/softlayer/softlayer-go v1.1.2 // indirect @@ -210,9 +225,9 @@ require ( google.golang.org/grpc v1.53.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/ns1/ns1-go.v2 v2.7.6 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.4.0 // indirect ) diff --git a/go.sum b/go.sum index ae94432..39b642d 100644 --- a/go.sum +++ b/go.sum @@ -60,6 +60,7 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v4.0.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= @@ -107,9 +108,35 @@ github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0 github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= -github.com/aws/aws-sdk-go v1.39.0 h1:74BBwkEmiqBbi2CGflEh34l0YNtIibTjZsibGarkNjo= -github.com/aws/aws-sdk-go v1.39.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go-v2 v1.19.0 h1:klAT+y3pGFBU/qVf1uzwttpBbiuozJYWzNLHioyDJ+k= +github.com/aws/aws-sdk-go-v2 v1.19.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2/config v1.18.28 h1:TINEaKyh1Td64tqFvn09iYpKiWjmHYrG1fa91q2gnqw= +github.com/aws/aws-sdk-go-v2/config v1.18.28/go.mod h1:nIL+4/8JdAuNHEjn/gPEXqtnS02Q3NXB/9Z7o5xE4+A= +github.com/aws/aws-sdk-go-v2/credentials v1.13.27 h1:dz0yr/yR1jweAnsCx+BmjerUILVPQ6FS5AwF/OyG1kA= +github.com/aws/aws-sdk-go-v2/credentials v1.13.27/go.mod h1:syOqAek45ZXZp29HlnRS/BNgMIW6uiRmeuQsz4Qh2UE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 h1:kP3Me6Fy3vdi+9uHd7YLr6ewPxRL+PU6y15urfTaamU= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5/go.mod h1:Gj7tm95r+QsDoN2Fhuz/3npQvcZbkEf5mL70n3Xfluc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 h1:hMUCiE3Zi5AHrRNGf5j985u0WyqI6r2NULhUfo0N/No= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35/go.mod h1:ipR5PvpSPqIqL5Mi82BxLnfMkHVbmco8kUwO2xrCi0M= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 h1:yOpYx+FTBdpk/g+sBU6Cb1H0U/TLEcYYp66mYqsPpcc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29/go.mod h1:M/eUABlDbw2uVrdAn+UsI6M727qp2fxkp8K0ejcBDUY= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 h1:8r5m1BoAWkn0TDC34lUculryf7nUF25EgIMdjvGCkgo= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36/go.mod h1:Rmw2M1hMVTwiUhjwMoIBFWFJMhvJbct06sSidxInkhY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 h1:IiDolu/eLmuB18DRZibj77n1hHQT7z12jnGO7Ze3pLc= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29/go.mod h1:fDbkK4o7fpPXWn8YAPmTieAMuB9mk/VgvW64uaUqxd4= +github.com/aws/aws-sdk-go-v2/service/lightsail v1.27.2 h1:PwNeYoonBzmTdCztKiiutws3U24KrnDBuabzRfIlZY4= +github.com/aws/aws-sdk-go-v2/service/lightsail v1.27.2/go.mod h1:gQhLZrTEath4zik5ixIe6axvgY5jJrgSBDJ360Fxnco= +github.com/aws/aws-sdk-go-v2/service/route53 v1.28.4 h1:p4mTxJfCAyiTT4Wp6p/mOPa6j5MqCSRGot8qZwFs+Z0= +github.com/aws/aws-sdk-go-v2/service/route53 v1.28.4/go.mod h1:VBLWpaHvhQNeu7N9rMEf00SWeOONb/HvaDUxe/7b44k= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 h1:sWDv7cMITPcZ21QdreULwxOOAmE05JjEsT6fCDtDA9k= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.13/go.mod h1:DfX0sWuT46KpcqbMhJ9QWtxAIP1VozkDWf8VAkByjYY= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 h1:BFubHS/xN5bjl818QaroN6mQdjneYQ+AOx44KNXlyH4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13/go.mod h1:BzqsVVFduubEmzrVtUFQQIQdFqvUItF8XUq2EnS8Wog= +github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 h1:e5mnydVdCVWxP+5rPAGi2PYxC7u2OZgH1ypC114H04U= +github.com/aws/aws-sdk-go-v2/service/sts v1.19.3/go.mod h1:yVGZA1CPkmUhBdA039jXNJJG7/6t+G+EBWmFq23xqnY= github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04= +github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= +github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -259,8 +286,8 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-acme/lego/v4 v4.13.3 h1:aZ1S9FXIkCWG3Uw/rZKSD+MOuO8ZB1t6p9VCg6jJiNY= -github.com/go-acme/lego/v4 v4.13.3/go.mod h1:c/iodVGMeBXG/+KiQczoNkySo3YLWTVa0kiyeVd/FHc= +github.com/go-acme/lego/v4 v4.14.2 h1:/D/jqRgLi8Cbk33sLGtu2pX2jEg3bGJWHyV8kFuUHGM= +github.com/go-acme/lego/v4 v4.14.2/go.mod h1:kBXxbeTg0x9AgaOYjPSwIeJy3Y33zTz+tMD16O4MO6c= github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs= github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= @@ -672,6 +699,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= @@ -1024,11 +1052,15 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAAxrQxRHEu7FkapwTuI2WmL1rw4g= github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= +github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nrdcg/auroradns v1.1.0 h1:KekGh8kmf2MNwqZVVYo/fw/ZONt8QMEmbMFOeljteWo= github.com/nrdcg/auroradns v1.1.0/go.mod h1:O7tViUZbAcnykVnrGkXzIJTHoQCHcgalgAe6X1mzHfk= +github.com/nrdcg/bunny-go v0.0.0-20230728143221-c9dda82568d9 h1:qpB3wZR4+MPK92cTC9zZPnndkJgDgPvQqPUAgVc1NXU= +github.com/nrdcg/bunny-go v0.0.0-20230728143221-c9dda82568d9/go.mod h1:HUoHXDrFvidN1NK9Wb/mZKNOfDNutKkzF2Pg71M9hHA= github.com/nrdcg/desec v0.7.0 h1:iuGhi4pstF3+vJWwt292Oqe2+AsSPKDynQna/eu1fDs= github.com/nrdcg/desec v0.7.0/go.mod h1:e1uRqqKv1mJdd5+SQROAhmy75lKMphLzWIuASLkpeFY= github.com/nrdcg/dnspod-go v0.4.0 h1:c/jn1mLZNKF3/osJ6mz3QPxTudvPArXTjpkmYj0uK6U= @@ -1124,8 +1156,8 @@ github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6 github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw= github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg= github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0= -github.com/ovh/go-ovh v1.4.1 h1:VBGa5wMyQtTP7Zb+w97zRCh9sLtM/2YKRyy+MEJmWaM= -github.com/ovh/go-ovh v1.4.1/go.mod h1:6bL6pPyUT7tBfI0pqOegJgRjgjuO+mOo+MyXd1EEC0M= +github.com/ovh/go-ovh v1.4.2 h1:ub4jVK6ERbiBTo4y5wbLCjeKCjGY+K36e7BviW+MaAU= +github.com/ovh/go-ovh v1.4.2/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY= github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= @@ -1241,8 +1273,6 @@ github.com/shurcooL/highlight_go v0.0.0-20170515013102-78fb10f4a5f8/go.mod h1:UD github.com/shurcooL/octicon v0.0.0-20180602230221-c42b0e3b24d9/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/simplesurance/bunny-go v0.0.0-20221115111006-e11d9dc91f04 h1:ZTzdx88+AcnjqUfJwnz89UBrMSBQ1NEysg9u5d+dU9c= -github.com/simplesurance/bunny-go v0.0.0-20221115111006-e11d9dc91f04/go.mod h1:5KS21fpch8TIMyAUv/qQqTa3GZfBDYgjaZbd2KXKYfg= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.1.0/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= @@ -1877,6 +1907,8 @@ gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/ns1/ns1-go.v2 v2.7.6 h1:mCPl7q0jbIGACXvGBljAuuApmKZo3rRi4tlRIEbMvjA= gopkg.in/ns1/ns1-go.v2 v2.7.6/go.mod h1:GMnKY+ZuoJ+lVLL+78uSTjwTz2jMazq6AfGKQOYhsPk= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= diff --git a/package-lock.json b/package-lock.json index 9118a91..442bfae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cosmos-server", - "version": "0.8.3", + "version": "0.10.0-unstable16", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cosmos-server", - "version": "0.8.3", + "version": "0.10.0-unstable16", "dependencies": { "@ant-design/colors": "^6.0.0", "@ant-design/icons": "^4.7.0", @@ -36,6 +36,7 @@ "react": "^18.2.0", "react-apexcharts": "^1.4.0", "react-color": "^2.19.3", + "react-cookie": "^6.1.1", "react-copy-to-clipboard": "^5.1.0", "react-device-detect": "^2.2.2", "react-dom": "^18.2.0", @@ -3708,6 +3709,11 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" }, + "node_modules/@types/cookie": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.2.tgz", + "integrity": "sha512-DBpRoJGKJZn7RY92dPrgoMew8xCWc2P71beqsjyhEI/Ds9mOyVmBwtekyfhpwFIVt1WrxTonFifiOZ62V8CnNA==" + }, "node_modules/@types/hast": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", @@ -8900,6 +8906,19 @@ "react": "*" } }, + "node_modules/react-cookie": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-6.1.1.tgz", + "integrity": "sha512-fuFRpf8LH6SfmVMowDUIRywJF5jAUDUWrm0EI5VdXfTl5bPcJ7B0zWbuYpT0Tvikx7Gs18MlvAT+P+744dUz2g==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.1", + "hoist-non-react-statics": "^3.3.2", + "universal-cookie": "^6.0.0" + }, + "peerDependencies": { + "react": ">= 16.3.0" + } + }, "node_modules/react-copy-to-clipboard": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", @@ -10368,6 +10387,15 @@ "node": ">=4" } }, + "node_modules/universal-cookie": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-6.1.1.tgz", + "integrity": "sha512-33S9x3CpdUnnjwTNs2Fgc41WGve2tdLtvaK2kPSbZRc5pGpz2vQFbRWMxlATsxNNe/Cy8SzmnmbuBM85jpZPtA==", + "dependencies": { + "@types/cookie": "^0.5.1", + "cookie": "^0.5.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", diff --git a/package.json b/package.json index bcbcb59..f8d4843 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cosmos-server", - "version": "0.9.21", + "version": "0.10.0-unstable31", "description": "", "main": "test-server.js", "bugs": { @@ -36,6 +36,7 @@ "react": "^18.2.0", "react-apexcharts": "^1.4.0", "react-color": "^2.19.3", + "react-cookie": "^6.1.1", "react-copy-to-clipboard": "^5.1.0", "react-device-detect": "^2.2.2", "react-dom": "^18.2.0", @@ -63,13 +64,12 @@ "scripts": { "client": "vite", "client-build": "vite build --base=/cosmos-ui/", - "start": "env CONFIG_FILE=./config_dev.json EZ=UTC ACME_STAGING=true build/cosmos", + "start": "env COSMOS_CONFIG_FOLDER=/mnt/e/work/Cosmos-Server/zz_test_config/ CONFIG_FILE=./config_dev.json EZ=UTC ACME_STAGING=true build/cosmos", "build": "sh build.sh", "dev": "npm run build && npm run start", "dockerdevbuild": "sh build.sh && docker build -f dockerfile.local --tag cosmos-dev .", - "dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run -d -p 7200:443 -p 80:80 -p 443:443 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG -v /:/mnt/host --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev", - "dockerdev": "npm run dockerdevbuild && npm run dockerdevrun", - "dockerdevclient": "npm run client-build && npm run dockerdevbuild && npm run dockerdevrun", + "dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run --cap-add NET_ADMIN -d -p 7200:443 -p 80:80 -p 53:53 -p 443:443 -p 4242:4242 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG -v /:/mnt/host --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev", + "dockerdev": "npm run client-build && npm run dockerdevbuild && npm run dockerdevrun", "demo": "vite build --base=/cosmos-ui/ --mode demo", "devdemo": "vite --mode demo" }, diff --git a/readme.md b/readme.md index eb3ce03..b4581e1 100644 --- a/readme.md +++ b/readme.md @@ -7,8 +7,7 @@

null null Clayton Stone -Billy Das -Seraph91P +null

--- @@ -45,6 +44,7 @@ Cosmos is a: * **Reverse-Proxy** 🔄🔗 Targeting containers, other servers, or serving static folders / SPA with **automatic HTTPS**, and a **nice UI** * **Authentication Server** 👦👩 With strong security, **multi-factor authentication** and multiple strategies (**OpenId**, forward headers, HTML) * **Container manager** 🐋🔧 To easily manage your containers and their settings, keep them up to date as well as audit their security. Includes docker-compose support! + * **VPN** 🌐🔒 To securely access your applications from anywhere, without having to open ports on your router. * **Identity Provider** 👦👩 To easily manage your users, **invite your friends and family** to your applications without awkardly sharing credentials. Let them request a password change with an email rather than having you unlock their account manually! * **SmartShield technology** 🧠🛡 Automatically secure your applications without manual adjustments (see below for more details). Includes anti-bot and anti-DDOS strategies. @@ -146,15 +146,17 @@ Note that **you are allowed** to use it to host a monetized business website, a Installation is simple using Docker: ``` -docker run -d -p 80:80 -p 443:443 --privileged --name cosmos-server -h cosmos-server --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /:/mnt/host -v /var/lib/cosmos:/config azukaar/cosmos-server:latest +docker run -d -p 80:80 -p 443:443 -p 4242:4242/udp --privileged --name cosmos-server -h cosmos-server --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /:/mnt/host -v /var/lib/cosmos:/config azukaar/cosmos-server:latest ``` in this command, `-v /:/mnt/host` is optional and allow to manage folders from Cosmos, you can remove it if you don't want it but you will have to create your container's bind folders manually. -`--privileged` is also optional, but it is required if you use hardening software like AppArmor or SELinux, as they restrict access to the docker socket. +`--privileged` is also optional, but it is required if you use hardening software like AppArmor or SELinux, as they restrict access to the docker socket. It is also required for Constellation to work. If you don't want to use it, you can add the following capabilities: NET_ADMIN for Constellation. Once installed, simply go to `http://your-server-ip` and follow the instructions of the setup wizard. +Port 4242 is a UDP port used for the Constellation VPN. + make sure you expose the right ports (by default 80 / 443). It is best to keep those ports intacts, as Cosmos is meant to run as your reverse proxy. Trying to setup Cosmos behind another reverse proxy is possible but will only create headaches. You also need to keep the docker socket mounted, as Cosmos needs to be able to manage your containers. diff --git a/src/background.go b/src/background.go index fc5eda4..b096d0f 100644 --- a/src/background.go +++ b/src/background.go @@ -54,7 +54,7 @@ func UploadBackground(w http.ResponseWriter, req *http.Request) { } // create a new file in the config directory - dst, err := os.Create("/config/background" + ext) + dst, err := os.Create(utils.CONFIGFOLDER + "background" + ext) if err != nil { utils.HTTPError(w, "Error creating destination file", http.StatusInternalServerError, "FILE004") return @@ -99,7 +99,7 @@ func GetBackground(w http.ResponseWriter, req *http.Request) { if(req.Method == "GET") { // get the background image - bg, err := ioutil.ReadFile("/config/background." + ext) + bg, err := ioutil.ReadFile(utils.CONFIGFOLDER + "background." + ext) if err != nil { utils.HTTPError(w, "Error reading background image", http.StatusInternalServerError, "FILE003") return diff --git a/src/configapi/get.go b/src/configapi/get.go index fac06ea..7af53bc 100644 --- a/src/configapi/get.go +++ b/src/configapi/get.go @@ -42,6 +42,7 @@ func ConfigApiGet(w http.ResponseWriter, req *http.Request) { "data": config, "updates": utils.UpdateAvailable, "hostname": os.Getenv("HOSTNAME"), + "isAdmin": isAdmin, }) } else { utils.Error("SettingGet: Method not allowed" + req.Method, nil) diff --git a/src/configapi/set.go b/src/configapi/set.go index 85b5624..a2aad63 100644 --- a/src/configapi/set.go +++ b/src/configapi/set.go @@ -5,6 +5,7 @@ import ( "encoding/json" "github.com/azukaar/cosmos-server/src/utils" "github.com/azukaar/cosmos-server/src/authorizationserver" + "github.com/azukaar/cosmos-server/src/constellation" ) func ConfigApiSet(w http.ResponseWriter, req *http.Request) { @@ -43,6 +44,7 @@ func ConfigApiSet(w http.ResponseWriter, req *http.Request) { utils.DisconnectDB() authorizationserver.Init() utils.RestartHTTPServer() + constellation.RestartNebula() json.NewEncoder(w).Encode(map[string]interface{}{ "status": "OK", diff --git a/src/constellation/DNS.go b/src/constellation/DNS.go new file mode 100644 index 0000000..40864cd --- /dev/null +++ b/src/constellation/DNS.go @@ -0,0 +1,190 @@ +package constellation + +import ( + "time" + "strconv" + "strings" + "io/ioutil" + + "github.com/miekg/dns" + "github.com/azukaar/cosmos-server/src/utils" +) + +var DNSBlacklist = map[string]bool{} + +func externalLookup(client *dns.Client, r *dns.Msg, serverAddr string) (*dns.Msg, time.Duration, error) { + rCopy := r.Copy() // Create a copy of the request to forward + rCopy.Id = dns.Id() // Assign a new ID for the forwarded request + + // Enable DNSSEC + rCopy.SetEdns0(4096, true) + rCopy.CheckingDisabled = false + rCopy.MsgHdr.AuthenticatedData = true + + return client.Exchange(rCopy, serverAddr) +} + +func handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) { + config := utils.GetMainConfig() + DNSFallback := config.ConstellationConfig.DNSFallback + + if DNSFallback == "" { + DNSFallback = "8.8.8.8:53" + } + + m := new(dns.Msg) + m.SetReply(r) + m.Authoritative = true + + customHandled := false + + // []string hostnames + hostnames := utils.GetAllHostnames(false, true) + + if !customHandled { + customDNSEntries := config.ConstellationConfig.CustomDNSEntries + + // Overwrite local hostnames with custom entries + for _, q := range r.Question { + for _, entry := range customDNSEntries { + hostname := entry.Key + ip := entry.Value + + if strings.HasSuffix(q.Name, hostname + ".") && q.Qtype == dns.TypeA { + utils.Debug("DNS Overwrite " + hostname + " with " + ip) + rr, _ := dns.NewRR(q.Name + " A " + ip) + m.Answer = append(m.Answer, rr) + customHandled = true + } + } + } + } + + if !customHandled { + // Overwrite local hostnames with Constellation IP + for _, q := range r.Question { + utils.Debug("DNS Question " + q.Name) + for _, hostname := range hostnames { + if strings.HasSuffix(q.Name, hostname + ".") && q.Qtype == dns.TypeA { + utils.Debug("DNS Overwrite " + hostname + " with 192.168.201.1") + rr, _ := dns.NewRR(q.Name + " A 192.168.201.1") + m.Answer = append(m.Answer, rr) + customHandled = true + } + } + } + } + + if !customHandled { + // Block blacklisted domains + for _, q := range r.Question { + noDot := strings.TrimSuffix(q.Name, ".") + if DNSBlacklist[noDot] { + if q.Qtype == dns.TypeA { + utils.Debug("DNS Block " + noDot) + rr, _ := dns.NewRR(q.Name + " A 0.0.0.0") + m.Answer = append(m.Answer, rr) + } + + customHandled = true + } + } + } + + // If not custom handled, use external DNS + if !customHandled { + client := new(dns.Client) + externalResponse, time, err := externalLookup(client, r, DNSFallback) + if err != nil { + utils.Error("Failed to forward query:", err) + return + } + utils.Debug("DNS Forwarded DNS query to "+DNSFallback+" in " + time.String()) + + externalResponse.Id = r.Id + + m = externalResponse + } + + w.WriteMsg(m) +} + +func isDomain(domain string) bool { + // contains . and at least a letter and no special characters invalid in a domain + if strings.Contains(domain, ".") && strings.ContainsAny(domain, "abcdefghijklmnopqrstuvwxyz") && !strings.ContainsAny(domain, " !@#$%^&*()+=[]{}\\|;:'\",/<>?") { + return true + } + return false +} + +func loadRawBlockList(DNSBlacklistRaw string) { + DNSBlacklistArray := strings.Split(string(DNSBlacklistRaw), "\n") + for _, domain := range DNSBlacklistArray { + if domain != "" && !strings.HasPrefix(domain, "#") { + splitDomain := strings.Split(domain, " ") + if len(splitDomain) == 1 && isDomain(splitDomain[0]) { + DNSBlacklist[splitDomain[0]] = true + } else if len(splitDomain) == 2 { + if isDomain(splitDomain[0]) { + DNSBlacklist[splitDomain[0]] = true + } else if isDomain(splitDomain[1]) { + DNSBlacklist[splitDomain[1]] = true + } + } + } + } +} + +func InitDNS() { + config := utils.GetMainConfig() + DNSPort := config.ConstellationConfig.DNSPort + DNSBlockBlacklist := config.ConstellationConfig.DNSBlockBlacklist + + if DNSPort == "" { + DNSPort = "53" + } + + if DNSBlockBlacklist { + DNSBlacklist = map[string]bool{} + blacklistPath := utils.CONFIGFOLDER + "dns-blacklist.txt" + + utils.Log("Loading DNS blacklist from " + blacklistPath) + + fileExist := utils.FileExists(blacklistPath) + if fileExist { + DNSBlacklistRaw, err := ioutil.ReadFile(blacklistPath) + if err != nil { + utils.Error("Failed to load DNS blacklist", err) + } else { + loadRawBlockList(string(DNSBlacklistRaw)) + } + } else { + utils.Log("No DNS blacklist found") + } + + // download additional blocklists from config.DNSAdditionalBlocklists []string + for _, url := range config.ConstellationConfig.DNSAdditionalBlocklists { + utils.Log("Downloading DNS blacklist from " + url) + DNSBlacklistRaw, err := utils.DownloadFile(url) + if err != nil { + utils.Error("Failed to download DNS blacklist", err) + } else { + loadRawBlockList(DNSBlacklistRaw) + } + } + + utils.Log("Loaded " + strconv.Itoa(len(DNSBlacklist)) + " domains") + } + + if(!config.ConstellationConfig.DNSDisabled) { + go (func() { + dns.HandleFunc(".", handleDNSRequest) + server := &dns.Server{Addr: ":" + DNSPort, Net: "udp"} + + utils.Log("Starting DNS server on :" + DNSPort) + if err := server.ListenAndServe(); err != nil { + utils.Fatal("Failed to start server: %s\n", err) + } + })() + } +} diff --git a/src/constellation/api_devices_block.go b/src/constellation/api_devices_block.go new file mode 100644 index 0000000..14568de --- /dev/null +++ b/src/constellation/api_devices_block.go @@ -0,0 +1,101 @@ +package constellation + +import ( + "net/http" + "encoding/json" + + "github.com/azukaar/cosmos-server/src/utils" +) + +type DeviceBlockRequestJSON struct { + Nickname string `json:"nickname",validate:"required,min=3,max=32,alphanum"` + DeviceName string `json:"deviceName",validate:"required,min=3,max=32,alphanum"` + Block bool `json:"block",omitempty` +} + +func DeviceBlock(w http.ResponseWriter, req *http.Request) { + if(req.Method == "POST") { + var request DeviceBlockRequestJSON + err1 := json.NewDecoder(req.Body).Decode(&request) + if err1 != nil { + utils.Error("ConstellationDeviceBlocking: Invalid User Request", err1) + utils.HTTPError(w, "Device Creation Error", + http.StatusInternalServerError, "DB001") + return + } + + errV := utils.Validate.Struct(request) + if errV != nil { + utils.Error("DeviceBlocking: Invalid User Request", errV) + utils.HTTPError(w, "Device Creation Error: " + errV.Error(), + http.StatusInternalServerError, "DB002") + return + } + + nickname := utils.Sanitize(request.Nickname) + deviceName := utils.Sanitize(request.DeviceName) + + if utils.AdminOrItselfOnly(w, req, nickname) != nil { + return + } + + utils.Log("ConstellationDeviceBlocking: Blocking Device " + deviceName) + + c, errCo := utils.GetCollection(utils.GetRootAppId(), "devices") + if errCo != nil { + utils.Error("Database Connect", errCo) + utils.HTTPError(w, "Database", http.StatusInternalServerError, "DB001") + return + } + + device := utils.Device{} + + utils.Debug("ConstellationDeviceBlocking: Blocking Device " + deviceName) + + err2 := c.FindOne(nil, map[string]interface{}{ + "DeviceName": deviceName, + "Nickname": nickname, + "Blocked": false, + }).Decode(&device) + + if err2 == nil { + utils.Debug("ConstellationDeviceBlocking: Found Device " + deviceName) + + _, err3 := c.UpdateOne(nil, map[string]interface{}{ + "DeviceName": deviceName, + "Nickname": nickname, + }, map[string]interface{}{ + "$set": map[string]interface{}{ + "Blocked": request.Block, + }, + }) + + if err3 != nil { + utils.Error("DeviceBlocking: Error while updating device", err3) + utils.HTTPError(w, "Device Creation Error: " + err3.Error(), + http.StatusInternalServerError, "DB001") + return + } + + if request.Block { + utils.Log("ConstellationDeviceBlocking: Device " + deviceName + " blocked") + } else { + utils.Log("ConstellationDeviceBlocking: Device " + deviceName + " unblocked") + } + } else { + utils.Error("DeviceBlocking: Error while finding device", err2) + utils.HTTPError(w, "Device Creation Error: " + err2.Error(), + http.StatusInternalServerError, "DB001") + return + } + + + json.NewEncoder(w).Encode(map[string]interface{}{ + "status": "OK", + }) + } else { + utils.Error("DeviceBlocking: Method not allowed" + req.Method, nil) + utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") + return + } +} \ No newline at end of file diff --git a/src/constellation/api_devices_config.go b/src/constellation/api_devices_config.go new file mode 100644 index 0000000..b9fe8f5 --- /dev/null +++ b/src/constellation/api_devices_config.go @@ -0,0 +1,41 @@ +package constellation + +// import ( +// "net/http" +// "encoding/json" +// "math/rand" +// "time" +// "net" + +// "github.com/azukaar/cosmos-server/src/utils" +// ) + +// func DeviceConfig(w http.ResponseWriter, req *http.Request) { +// time.Sleep(time.Duration(rand.Float64()*2)*time.Second) + +// if(req.Method == "GET") { + +// ip, _, err := net.SplitHostPort(req.RemoteAddr) +// if err != nil { +// http.Error(w, "Invalid request", http.StatusBadRequest) +// return +// } + +// // get authorization header +// auth := req.Header.Get("Authorization") +// if auth == "" { +// http.Error(w, "Unauthorized", http.StatusUnauthorized) +// return +// } + +// // remove "Bearer " from auth header +// auth = strings.Replace(auth, "Bearer ", "", 1) + + + +// } else { +// utils.Error("DeviceConfig: Method not allowed" + req.Method, nil) +// utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") +// return +// } +// } \ No newline at end of file diff --git a/src/constellation/api_devices_create.go b/src/constellation/api_devices_create.go new file mode 100644 index 0000000..995669b --- /dev/null +++ b/src/constellation/api_devices_create.go @@ -0,0 +1,182 @@ +package constellation + +import ( + "net/http" + "encoding/json" + "go.mongodb.org/mongo-driver/mongo" + + "github.com/azukaar/cosmos-server/src/utils" +) + +type DeviceCreateRequestJSON struct { + DeviceName string `json:"deviceName",validate:"required,min=3,max=32,alphanum"` + IP string `json:"ip",validate:"required,ipv4"` + PublicKey string `json:"publicKey",omitempty` + + // for devices only + Nickname string `json:"nickname",validate:"max=32,alphanum",omitempty` + + // for lighthouse only + IsLighthouse bool `json:"isLighthouse",omitempty` + IsRelay bool `json:"isRelay",omitempty` + PublicHostname string `json:"PublicHostname",omitempty` + Port string `json:"port",omitempty` +} + +func DeviceCreate(w http.ResponseWriter, req *http.Request) { + if(req.Method == "POST") { + var request DeviceCreateRequestJSON + err1 := json.NewDecoder(req.Body).Decode(&request) + if err1 != nil { + utils.Error("ConstellationDeviceCreation: Invalid User Request", err1) + utils.HTTPError(w, "Device Creation Error", + http.StatusInternalServerError, "DC001") + return + } + + errV := utils.Validate.Struct(request) + if errV != nil { + utils.Error("DeviceCreation: Invalid User Request", errV) + utils.HTTPError(w, "Device Creation Error: " + errV.Error(), + http.StatusInternalServerError, "DC002") + return + } + + nickname := utils.Sanitize(request.Nickname) + deviceName := utils.Sanitize(request.DeviceName) + APIKey := utils.GenerateRandomString(32) + + if utils.AdminOrItselfOnly(w, req, nickname) != nil { + return + } + + utils.Log("ConstellationDeviceCreation: Creating Device " + deviceName) + + c, errCo := utils.GetCollection(utils.GetRootAppId(), "devices") + if errCo != nil { + utils.Error("Database Connect", errCo) + utils.HTTPError(w, "Database", http.StatusInternalServerError, "DB001") + return + } + + device := utils.Device{} + + utils.Debug("ConstellationDeviceCreation: Creating Device " + deviceName) + + err2 := c.FindOne(nil, map[string]interface{}{ + "DeviceName": deviceName, + "Blocked": false, + }).Decode(&device) + + if err2 == mongo.ErrNoDocuments { + + cert, key, fingerprint, err := generateNebulaCert(deviceName, request.IP, request.PublicKey, false) + + if err != nil { + utils.Error("DeviceCreation: Error while creating Device", err) + utils.HTTPError(w, "Device Creation Error: " + err.Error(), + http.StatusInternalServerError, "DC001") + return + } + + if request.IsLighthouse && request.Nickname != "" { + utils.Error("DeviceCreation: Lighthouse cannot belong to a user", nil) + utils.HTTPError(w, "Device Creation Error: Lighthouse cannot have a nickname", + http.StatusInternalServerError, "DC003") + return + } + + if err != nil { + utils.Error("DeviceCreation: Error while getting fingerprint", err) + utils.HTTPError(w, "Device Creation Error: " + err.Error(), + http.StatusInternalServerError, "DC007") + return + } + + _, err3 := c.InsertOne(nil, map[string]interface{}{ + "Nickname": nickname, + "DeviceName": deviceName, + "PublicKey": key, + "IP": request.IP, + "IsLighthouse": request.IsLighthouse, + "IsRelay": request.IsRelay, + "PublicHostname": request.PublicHostname, + "Port": request.Port, + "Fingerprint": fingerprint, + "APIKey": APIKey, + "Blocked": false, + }) + + if err3 != nil { + utils.Error("DeviceCreation: Error while creating Device", err3) + utils.HTTPError(w, "Device Creation Error: " + err.Error(), + http.StatusInternalServerError, "DC004") + return + } + + capki, err := getCApki() + if err != nil { + utils.Error("DeviceCreation: Error while reading ca.crt", err) + utils.HTTPError(w, "Device Creation Error: " + err.Error(), + http.StatusInternalServerError, "DC006") + return + } + + lightHousesList := []utils.ConstellationDevice{} + if request.IsLighthouse { + lightHousesList, err = GetAllLightHouses() + } + + // read configYml from config/nebula.yml + configYml, err := getYAMLClientConfig(deviceName, utils.CONFIGFOLDER + "nebula.yml", capki, cert, key, APIKey, utils.ConstellationDevice{ + Nickname: nickname, + DeviceName: deviceName, + PublicKey: key, + IP: request.IP, + IsLighthouse: request.IsLighthouse, + IsRelay: request.IsRelay, + PublicHostname: request.PublicHostname, + Port: request.Port, + APIKey: APIKey, + }) + + if err != nil { + utils.Error("DeviceCreation: Error while reading config", err) + utils.HTTPError(w, "Device Creation Error: " + err.Error(), + http.StatusInternalServerError, "DC005") + return + } + + json.NewEncoder(w).Encode(map[string]interface{}{ + "status": "OK", + "data": map[string]interface{}{ + "Nickname": nickname, + "DeviceName": deviceName, + "PublicKey": key, + "PrivateKey": cert, + "IP": request.IP, + "Config": configYml, + "CA": capki, + "IsLighthouse": request.IsLighthouse, + "IsRelay": request.IsRelay, + "PublicHostname": request.PublicHostname, + "Port": request.Port, + "LighthousesList": lightHousesList, + }, + }) + } else if err2 == nil { + utils.Error("DeviceCreation: Device already exists", nil) + utils.HTTPError(w, "Device name already exists", http.StatusConflict, "DC002") + return + } else { + utils.Error("DeviceCreation: Error while finding device", err2) + utils.HTTPError(w, "Device Creation Error: " + err2.Error(), + http.StatusInternalServerError, "DC001") + return + } + } else { + utils.Error("DeviceCreation: Method not allowed" + req.Method, nil) + utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") + return + } +} \ No newline at end of file diff --git a/src/constellation/api_devices_index.go b/src/constellation/api_devices_index.go new file mode 100644 index 0000000..38b2a12 --- /dev/null +++ b/src/constellation/api_devices_index.go @@ -0,0 +1,18 @@ +package constellation + +import ( + "net/http" + "github.com/azukaar/cosmos-server/src/utils" +) + +func ConstellationAPIDevices(w http.ResponseWriter, req *http.Request) { + if (req.Method == "GET") { + DeviceList(w, req) + } else if (req.Method == "POST") { + DeviceCreate(w, req) + } else { + utils.Error("UserRoute: Method not allowed" + req.Method, nil) + utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") + return + } +} \ No newline at end of file diff --git a/src/constellation/api_devices_list.go b/src/constellation/api_devices_list.go new file mode 100644 index 0000000..df8b151 --- /dev/null +++ b/src/constellation/api_devices_list.go @@ -0,0 +1,73 @@ +package constellation + +import ( + "net/http" + "encoding/json" + + + "github.com/azukaar/cosmos-server/src/utils" +) + +func DeviceList(w http.ResponseWriter, req *http.Request) { + // Check for GET method + if req.Method != "GET" { + utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP002") + return + } + + if utils.LoggedInOnly(w, req) != nil { + return + } + + isAdmin := utils.IsAdmin(req) + + // Connect to the collection + c, errCo := utils.GetCollection(utils.GetRootAppId(), "devices") + if errCo != nil { + utils.Error("Database Connect", errCo) + utils.HTTPError(w, "Database", http.StatusInternalServerError, "DB001") + return + } + + var devices []utils.ConstellationDevice + + // Check if user is an admin + if isAdmin { + // If admin, get all devices + cursor, err := c.Find(nil, map[string]interface{}{}) + if err != nil { + utils.Error("DeviceList: Error fetching devices", err) + utils.HTTPError(w, "Error fetching devices", http.StatusInternalServerError, "DL001") + return + } + defer cursor.Close(nil) + + if err = cursor.All(nil, &devices); err != nil { + utils.Error("DeviceList: Error decoding devices", err) + utils.HTTPError(w, "Error decoding devices", http.StatusInternalServerError, "DL002") + return + } + } else { + // If not admin, get user's devices based on their nickname + nickname := req.Header.Get("x-cosmos-user") + cursor, err := c.Find(nil, map[string]interface{}{"Nickname": nickname}) + if err != nil { + utils.Error("DeviceList: Error fetching devices", err) + utils.HTTPError(w, "Error fetching devices", http.StatusInternalServerError, "DL003") + return + } + defer cursor.Close(nil) + + if err = cursor.All(nil, &devices); err != nil { + utils.Error("DeviceList: Error decoding devices", err) + utils.HTTPError(w, "Error decoding devices", http.StatusInternalServerError, "DL004") + return + } + } + + // Respond with the list of devices + json.NewEncoder(w).Encode(map[string]interface{}{ + "status": "OK", + "data": devices, + }) +} diff --git a/src/constellation/api_nebula.go b/src/constellation/api_nebula.go new file mode 100644 index 0000000..0374760 --- /dev/null +++ b/src/constellation/api_nebula.go @@ -0,0 +1,99 @@ +package constellation + +import ( + "net/http" + "encoding/json" + "io/ioutil" + "os" + + "github.com/azukaar/cosmos-server/src/utils" +) + +func API_GetConfig(w http.ResponseWriter, req *http.Request) { + if utils.AdminOnly(w, req) != nil { + return + } + + if(req.Method == "GET") { + // read utils.CONFIGFOLDER + "nebula.yml" + config, err := ioutil.ReadFile(utils.CONFIGFOLDER + "nebula.yml") + + if err != nil { + utils.Error("SettingGet: error while reading nebula.yml", err) + utils.HTTPError(w, "Error while reading nebula.yml", http.StatusInternalServerError, "HTTP002") + return + } + + json.NewEncoder(w).Encode(map[string]interface{}{ + "status": "OK", + "data": string(config), + }) + } else { + utils.Error("SettingGet: Method not allowed" + req.Method, nil) + utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") + return + } +} + +func API_Restart(w http.ResponseWriter, req *http.Request) { + if utils.AdminOnly(w, req) != nil { + return + } + + if(req.Method == "GET") { + RestartNebula() + + utils.Log("Constellation: nebula restarted") + + json.NewEncoder(w).Encode(map[string]interface{}{ + "status": "OK", + }) + } else { + utils.Error("SettingGet: Method not allowed" + req.Method, nil) + utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") + return + } +} + +func API_Reset(w http.ResponseWriter, req *http.Request) { + if utils.AdminOnly(w, req) != nil { + return + } + + if(req.Method == "GET") { + ResetNebula() + + utils.Log("Constellation: nebula reset") + + json.NewEncoder(w).Encode(map[string]interface{}{ + "status": "OK", + }) + } else { + utils.Error("SettingGet: Method not allowed" + req.Method, nil) + utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") + return + } +} + +func API_GetLogs(w http.ResponseWriter, req *http.Request) { + if utils.AdminOnly(w, req) != nil { + return + } + + if(req.Method == "GET") { + logs, err := os.ReadFile(utils.CONFIGFOLDER+"nebula.log") + if err != nil { + utils.Error("Error reading file:", err) + return + } + + json.NewEncoder(w).Encode(map[string]interface{}{ + "status": "OK", + "data": string(logs), + }) + } else { + utils.Error("SettingGet: Method not allowed" + req.Method, nil) + utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") + return + } +} \ No newline at end of file diff --git a/src/constellation/api_nebula_connect.go b/src/constellation/api_nebula_connect.go new file mode 100644 index 0000000..168bb14 --- /dev/null +++ b/src/constellation/api_nebula_connect.go @@ -0,0 +1,47 @@ +package constellation + +import ( + "net/http" + "encoding/json" + "io/ioutil" + + + "github.com/azukaar/cosmos-server/src/utils" +) + +func API_ConnectToExisting(w http.ResponseWriter, req *http.Request) { + if utils.AdminOnly(w, req) != nil { + return + } + + if(req.Method == "POST") { + body, err := ioutil.ReadAll(req.Body) + if err != nil { + utils.Error("API_Restart: Invalid User Request", err) + utils.HTTPError(w, "API_Restart Error", + http.StatusInternalServerError, "AR001") + return + } + + config := utils.ReadConfigFromFile() + config.ConstellationConfig.Enabled = true + config.ConstellationConfig.SlaveMode = true + config.ConstellationConfig.DNSDisabled = true + // ConstellationHostname = + + // output utils.CONFIGFOLDER + "nebula.yml" + err = ioutil.WriteFile(utils.CONFIGFOLDER + "nebula.yml", body, 0644) + + utils.SetBaseMainConfig(config) + + RestartNebula() + + json.NewEncoder(w).Encode(map[string]interface{}{ + "status": "OK", + }) + } else { + utils.Error("SettingGet: Method not allowed" + req.Method, nil) + utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001") + return + } +} diff --git a/src/constellation/index.go b/src/constellation/index.go new file mode 100644 index 0000000..6fffcbd --- /dev/null +++ b/src/constellation/index.go @@ -0,0 +1,62 @@ +package constellation + +import ( + "github.com/azukaar/cosmos-server/src/utils" + "os" + "time" +) + +func Init() { + var err error + + // if date is > 1st of January 2024 + timeNow := time.Now() + if timeNow.Year() > 2024 || (timeNow.Year() == 2024 && timeNow.Month() > 1) { + utils.Error("Constellation: this preview version has expired, please update to use the lastest version of Constellation.", nil) + // disable constellation + configFile := utils.ReadConfigFromFile() + configFile.ConstellationConfig.Enabled = false + utils.SetBaseMainConfig(configFile) + return + } + + // if Constellation is enabled + if utils.GetMainConfig().ConstellationConfig.Enabled { + if !utils.GetMainConfig().ConstellationConfig.SlaveMode { + InitConfig() + + utils.Log("Initializing Constellation module...") + + // check if ca.crt exists + if _, err = os.Stat(utils.CONFIGFOLDER + "ca.crt"); os.IsNotExist(err) { + utils.Log("Constellation: ca.crt not found, generating...") + // generate ca.crt + generateNebulaCACert("Cosmos - " + utils.GetMainConfig().ConstellationConfig.ConstellationHostname) + } + + // check if cosmos.crt exists + if _, err := os.Stat(utils.CONFIGFOLDER + "cosmos.crt"); os.IsNotExist(err) { + utils.Log("Constellation: cosmos.crt not found, generating...") + // generate cosmos.crt + generateNebulaCert("cosmos", "192.168.201.1/24", "", true) + } + + // export nebula.yml + utils.Log("Constellation: exporting nebula.yml...") + err := ExportConfigToYAML(utils.GetMainConfig().ConstellationConfig, utils.CONFIGFOLDER + "nebula.yml") + + if err != nil { + utils.Error("Constellation: error while exporting nebula.yml", err) + } + } + + // start nebula + utils.Log("Constellation: starting nebula...") + err = startNebulaInBackground() + if err != nil { + utils.Error("Constellation: error while starting nebula", err) + } + + utils.Log("Constellation module initialized") + } +} \ No newline at end of file diff --git a/src/constellation/nebula.go b/src/constellation/nebula.go new file mode 100644 index 0000000..95c750e --- /dev/null +++ b/src/constellation/nebula.go @@ -0,0 +1,542 @@ +package constellation + +import ( + "github.com/azukaar/cosmos-server/src/utils" + "os/exec" + "os" + "fmt" + "errors" + "runtime" + "sync" + "gopkg.in/yaml.v2" + "strings" + "io/ioutil" + "strconv" + "encoding/json" + "io" + "github.com/natefinch/lumberjack" +) + +var logBuffer *lumberjack.Logger + +var ( + process *exec.Cmd + processMux sync.Mutex +) + +func binaryToRun() string { + if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" { + return "./nebula-arm" + } + return "./nebula" +} + +func startNebulaInBackground() error { + processMux.Lock() + defer processMux.Unlock() + + if process != nil { + return errors.New("nebula is already running") + } + + logBuffer = &lumberjack.Logger{ + Filename: utils.CONFIGFOLDER+"nebula.log", + MaxSize: 1, // megabytes + MaxBackups: 1, + MaxAge: 15, //days + Compress: false, + } + + process = exec.Command(binaryToRun(), "-config", utils.CONFIGFOLDER+"nebula.yml") + + // Set up multi-writer for stderr + process.Stderr = io.MultiWriter(logBuffer, os.Stderr) + + if utils.LoggingLevelLabels[utils.GetMainConfig().LoggingLevel] == utils.DEBUG { + // Set up multi-writer for stdout if in debug mode + process.Stdout = io.MultiWriter(logBuffer, os.Stdout) + } else { + process.Stdout = io.MultiWriter(logBuffer) + } + + // Start the process in the background + if err := process.Start(); err != nil { + return err + } + + utils.Log(fmt.Sprintf("%s started with PID %d\n", binaryToRun(), process.Process.Pid)) + return nil +} + +func stop() error { + processMux.Lock() + defer processMux.Unlock() + + if process == nil { + return nil + } + + if err := process.Process.Kill(); err != nil { + return err + } + process = nil + utils.Log("Stopped nebula.") + return nil +} + +func RestartNebula() { + stop() + Init() +} + +func ResetNebula() error { + stop() + utils.Log("Resetting nebula...") + os.RemoveAll(utils.CONFIGFOLDER + "nebula.yml") + os.RemoveAll(utils.CONFIGFOLDER + "ca.crt") + os.RemoveAll(utils.CONFIGFOLDER + "ca.key") + os.RemoveAll(utils.CONFIGFOLDER + "cosmos.crt") + os.RemoveAll(utils.CONFIGFOLDER + "cosmos.key") + // remove everything in db + + c, err := utils.GetCollection(utils.GetRootAppId(), "devices") + if err != nil { + return err + } + + _, err = c.DeleteMany(nil, map[string]interface{}{}) + if err != nil { + return err + } + + config := utils.ReadConfigFromFile() + config.ConstellationConfig.Enabled = false + config.ConstellationConfig.SlaveMode = false + config.ConstellationConfig.DNSDisabled = false + + utils.SetBaseMainConfig(config) + + Init() + + return nil +} + +func GetAllLightHouses() ([]utils.ConstellationDevice, error) { + c, err := utils.GetCollection(utils.GetRootAppId(), "devices") + if err != nil { + return []utils.ConstellationDevice{}, err + } + + var devices []utils.ConstellationDevice + + cursor, err := c.Find(nil, map[string]interface{}{ + "IsLighthouse": true, + "Blocked": false, + }) + cursor.All(nil, &devices) + + if err != nil { + return []utils.ConstellationDevice{}, err + } + + return devices, nil +} + +func GetBlockedDevices() ([]utils.ConstellationDevice, error) { + c, err := utils.GetCollection(utils.GetRootAppId(), "devices") + if err != nil { + return []utils.ConstellationDevice{}, err + } + + var devices []utils.ConstellationDevice + + cursor, err := c.Find(nil, map[string]interface{}{ + "Blocked": true, + }) + cursor.All(nil, &devices) + + if err != nil { + return []utils.ConstellationDevice{}, err + } + + return devices, nil +} + +func cleanIp(ip string) string { + return strings.Split(ip, "/")[0] +} + +func ExportConfigToYAML(overwriteConfig utils.ConstellationConfig, outputPath string) error { + // Combine defaultConfig and overwriteConfig + finalConfig := NebulaDefaultConfig + + if !overwriteConfig.PrivateNode { + finalConfig.StaticHostMap = map[string][]string{ + "192.168.201.1": []string{ + utils.GetMainConfig().ConstellationConfig.ConstellationHostname + ":4242", + }, + } + } else { + finalConfig.StaticHostMap = map[string][]string{} + } + + // for each lighthouse + lh, err := GetAllLightHouses() + if err != nil { + return err + } + + for _, l := range lh { + finalConfig.StaticHostMap[cleanIp(l.IP)] = []string{ + l.PublicHostname + ":" + l.Port, + } + } + + // add blocked devices + blockedDevices, err := GetBlockedDevices() + if err != nil { + return err + } + + for _, d := range blockedDevices { + finalConfig.PKI.Blocklist = append(finalConfig.PKI.Blocklist, d.Fingerprint) + } + + finalConfig.Lighthouse.AMLighthouse = !overwriteConfig.PrivateNode + + // add other lighthouses + finalConfig.Lighthouse.Hosts = []string{} + for _, l := range lh { + finalConfig.Lighthouse.Hosts = append(finalConfig.Lighthouse.Hosts, cleanIp(l.IP)) + } + + finalConfig.Relay.AMRelay = overwriteConfig.NebulaConfig.Relay.AMRelay + + finalConfig.Relay.Relays = []string{} + for _, l := range lh { + if l.IsRelay { + finalConfig.Relay.Relays = append(finalConfig.Relay.Relays, cleanIp(l.IP)) + } + } + + // Marshal the combined config to YAML + yamlData, err := yaml.Marshal(finalConfig) + if err != nil { + return err + } + + // delete nebula.yml if exists + if _, err := os.Stat(outputPath); err == nil { + os.Remove(outputPath) + } + + // Write YAML data to the specified file + yamlFile, err := os.Create(outputPath) + if err != nil { + return err + } + defer yamlFile.Close() + + _, err = yamlFile.Write(yamlData) + if err != nil { + return err + } + + return nil +} + +func getYAMLClientConfig(name, configPath, capki, cert, key, APIKey string, device utils.ConstellationDevice) (string, error) { + utils.Log("Exporting YAML config for " + name + " with file " + configPath) + + // Read the YAML config file + yamlData, err := ioutil.ReadFile(configPath) + if err != nil { + return "", err + } + + // Unmarshal the YAML data into a map interface + var configMap map[string]interface{} + err = yaml.Unmarshal(yamlData, &configMap) + if err != nil { + return "", err + } + + lh, err := GetAllLightHouses() + if err != nil { + return "", err + } + + if staticHostMap, ok := configMap["static_host_map"].(map[interface{}]interface{}); ok { + if !utils.GetMainConfig().ConstellationConfig.PrivateNode { + staticHostMap["192.168.201.1"] = []string{ + utils.GetMainConfig().ConstellationConfig.ConstellationHostname + ":4242", + } + } + + for _, l := range lh { + staticHostMap[cleanIp(l.IP)] = []string{ + l.PublicHostname + ":" + l.Port, + } + } + } else { + return "", errors.New("static_host_map not found in nebula.yml") + } + + // set lightHouse + if lighthouseMap, ok := configMap["lighthouse"].(map[interface{}]interface{}); ok { + lighthouseMap["am_lighthouse"] = device.IsLighthouse + + lighthouseMap["hosts"] = []string{} + if !utils.GetMainConfig().ConstellationConfig.PrivateNode { + lighthouseMap["hosts"] = append(lighthouseMap["hosts"].([]string), "192.168.201.1") + } + + for _, l := range lh { + if cleanIp(l.IP) != cleanIp(device.IP) { + lighthouseMap["hosts"] = append(lighthouseMap["hosts"].([]string), cleanIp(l.IP)) + } + } + } else { + return "", errors.New("lighthouse not found in nebula.yml") + } + + if pkiMap, ok := configMap["pki"].(map[interface{}]interface{}); ok { + pkiMap["ca"] = capki + pkiMap["cert"] = cert + pkiMap["key"] = key + } else { + return "", errors.New("pki not found in nebula.yml") + } + + if relayMap, ok := configMap["relay"].(map[interface{}]interface{}); ok { + relayMap["am_relay"] = device.IsRelay && device.IsLighthouse + relayMap["relays"] = []string{} + if utils.GetMainConfig().ConstellationConfig.NebulaConfig.Relay.AMRelay { + relayMap["relays"] = append(relayMap["relays"].([]string), "192.168.201.1") + } + + for _, l := range lh { + if l.IsRelay && l.IsLighthouse && cleanIp(l.IP) != cleanIp(device.IP) { + relayMap["relays"] = append(relayMap["relays"].([]string), cleanIp(l.IP)) + } + } + } else { + return "", errors.New("relay not found in nebula.yml") + } + + if listen, ok := configMap["listen"].(map[interface{}]interface{}); ok { + if device.Port != "" { + listen["port"] = device.Port + } else { + listen["port"] = "4242" + } + } else { + return "", errors.New("listen not found in nebula.yml") + } + + configMap["constellation_device_name"] = name + configMap["constellation_local_dns_overwrite"] = true + configMap["constellation_local_dns_overwrite_address"] = "192.168.201.1" + configMap["constellation_public_hostname"] = device.PublicHostname + configMap["constellation_api_key"] = APIKey + + // export configMap as YML + yamlData, err = yaml.Marshal(configMap) + if err != nil { + return "", err + } + + return string(yamlData), nil +} + +func getCApki() (string, error) { + // read config/ca.crt + caCrt, err := ioutil.ReadFile(utils.CONFIGFOLDER + "ca.crt") + if err != nil { + return "", err + } + + return string(caCrt), nil +} + +func killAllNebulaInstances() error { + processMux.Lock() + defer processMux.Unlock() + + cmd := exec.Command("ps", "-e", "-o", "pid,command") + output, err := cmd.CombinedOutput() + if err != nil { + return err + } + + lines := strings.Split(string(output), "\n") + for _, line := range lines { + if strings.Contains(line, binaryToRun()) { + fields := strings.Fields(line) + if len(fields) > 1 { + pid := fields[0] + pidInt, _ := strconv.Atoi(pid) + process, err := os.FindProcess(pidInt) + if err != nil { + return err + } + err = process.Kill() + if err != nil { + return err + } + utils.Log(fmt.Sprintf("Killed Nebula instance with PID %s\n", pid)) + } + } + } + + return nil +} + +func GetCertFingerprint(certPath string) (string, error) { + // nebula-cert print -json + var cmd *exec.Cmd + + cmd = exec.Command(binaryToRun() + "-cert", + "print", + "-json", + "-path", certPath, + ) + + // capture and parse output + output, err := cmd.CombinedOutput() + if err != nil { + utils.Error("Error while printing cert", err) + } + + var certInfo map[string]interface{} + err = json.Unmarshal(output, &certInfo) + if err != nil { + utils.Error("Error while unmarshalling cert information", err) + return "", err + } + + // Extract fingerprint, replace "fingerprint" with the actual key where the fingerprint is stored in the JSON output + fingerprint, ok := certInfo["fingerprint"].(string) + if !ok { + utils.Error("Fingerprint not found or not a string", nil) + return "", errors.New("fingerprint not found or not a string") + } + + return fingerprint, nil +} + +func generateNebulaCert(name, ip, PK string, saveToFile bool) (string, string, string, error) { + // Run the nebula-cert command + var cmd *exec.Cmd + + if(PK == "") { + cmd = exec.Command(binaryToRun() + "-cert", + "sign", + "-ca-crt", utils.CONFIGFOLDER + "ca.crt", + "-ca-key", utils.CONFIGFOLDER + "ca.key", + "-name", name, + "-ip", ip, + ) + } else { + // write PK to temp.cert + err := ioutil.WriteFile("./temp.key", []byte(PK), 0644) + if err != nil { + return "", "", "", fmt.Errorf("failed to write temp.key: %s", err) + } + cmd = exec.Command(binaryToRun() + "-cert", + "sign", + "-ca-crt", utils.CONFIGFOLDER + "ca.crt", + "-ca-key", utils.CONFIGFOLDER + "ca.key", + "-name", name, + "-ip", ip, + "-in-pub", "./temp.key", + ) + // delete temp.key + defer os.Remove("./temp.key") + } + + utils.Debug(cmd.String()) + + cmd.Stderr = os.Stderr + + if utils.LoggingLevelLabels[utils.GetMainConfig().LoggingLevel] == utils.DEBUG { + cmd.Stdout = os.Stdout + } else { + cmd.Stdout = nil + } + + cmd.Run() + + if cmd.ProcessState.ExitCode() != 0 { + return "", "", "", fmt.Errorf("nebula-cert exited with an error, check the Cosmos logs") + } + + // Read the generated certificate and key files + certPath := fmt.Sprintf("./%s.crt", name) + keyPath := fmt.Sprintf("./%s.key", name) + + utils.Debug("Reading certificate from " + certPath) + utils.Debug("Reading key from " + keyPath) + + fingerprint, err := GetCertFingerprint(certPath) + if err != nil { + return "", "", "", fmt.Errorf("failed to get certificate fingerprint: %s", err) + } + + certContent, errCert := ioutil.ReadFile(certPath) + if errCert != nil { + return "", "", "", fmt.Errorf("failed to read certificate file: %s", errCert) + } + + keyContent, errKey := ioutil.ReadFile(keyPath) + if errKey != nil { + return "", "", "", fmt.Errorf("failed to read key file: %s", errKey) + } + + if saveToFile { + cmd = exec.Command("mv", certPath, utils.CONFIGFOLDER + name + ".crt") + utils.Debug(cmd.String()) + cmd.Run() + cmd = exec.Command("mv", keyPath, utils.CONFIGFOLDER + name + ".key") + utils.Debug(cmd.String()) + cmd.Run() + } else { + // Delete the generated certificate and key files + if err := os.Remove(certPath); err != nil { + return "", "", "", fmt.Errorf("failed to delete certificate file: %s", err) + } + + if err := os.Remove(keyPath); err != nil { + return "", "", "", fmt.Errorf("failed to delete key file: %s", err) + } + } + + return string(certContent), string(keyContent), fingerprint, nil +} + +func generateNebulaCACert(name string) (error) { + // Run the nebula-cert command to generate CA certificate and key + cmd := exec.Command(binaryToRun() + "-cert", "ca", "-name", "\""+name+"\"") + + utils.Debug(cmd.String()) + + cmd.Stderr = os.Stderr + + if utils.LoggingLevelLabels[utils.GetMainConfig().LoggingLevel] == utils.DEBUG { + cmd.Stdout = os.Stdout + } else { + cmd.Stdout = nil + } + + if err := cmd.Run(); err != nil { + return fmt.Errorf("nebula-cert error: %s", err) + } + + // copy to /config/ca.* + cmd = exec.Command("mv", "./ca.crt", utils.CONFIGFOLDER + "ca.crt") + cmd.Run() + cmd = exec.Command("mv", "./ca.key", utils.CONFIGFOLDER + "ca.key") + cmd.Run() + + return nil +} \ No newline at end of file diff --git a/src/constellation/nebula_default.go b/src/constellation/nebula_default.go new file mode 100644 index 0000000..d36b850 --- /dev/null +++ b/src/constellation/nebula_default.go @@ -0,0 +1,113 @@ +package constellation + +import ( + "github.com/azukaar/cosmos-server/src/utils" +) + +var NebulaDefaultConfig utils.NebulaConfig + +func InitConfig() { + NebulaDefaultConfig = utils.NebulaConfig { + PKI: struct { + CA string `yaml:"ca"` + Cert string `yaml:"cert"` + Key string `yaml:"key"` + Blocklist []string `yaml:"blocklist"` + }{ + CA: utils.CONFIGFOLDER + "ca.crt", + Cert: utils.CONFIGFOLDER + "cosmos.crt", + Key: utils.CONFIGFOLDER + "cosmos.key", + Blocklist: []string{}, + }, + StaticHostMap: map[string][]string{ + + }, + Lighthouse: struct { + AMLighthouse bool `yaml:"am_lighthouse"` + Interval int `yaml:"interval"` + Hosts []string `yaml:"hosts"` + }{ + AMLighthouse: true, + Interval: 60, + Hosts: []string{}, + }, + Listen: struct { + Host string `yaml:"host"` + Port int `yaml:"port"` + }{ + Host: "0.0.0.0", + Port: 4242, + }, + Punchy: struct { + Punch bool `yaml:"punch"` + Respond bool `yaml:"respond"` + }{ + Punch: true, + Respond: true, + }, + Relay: struct { + AMRelay bool `yaml:"am_relay"` + UseRelays bool `yaml:"use_relays"` + Relays []string `yaml:"relays"` + }{ + AMRelay: true, + UseRelays: true, + Relays: []string{}, + }, + TUN: struct { + Disabled bool `yaml:"disabled"` + Dev string `yaml:"dev"` + DropLocalBroadcast bool `yaml:"drop_local_broadcast"` + DropMulticast bool `yaml:"drop_multicast"` + TxQueue int `yaml:"tx_queue"` + MTU int `yaml:"mtu"` + Routes []string `yaml:"routes"` + UnsafeRoutes []string `yaml:"unsafe_routes"` + }{ + Disabled: false, + Dev: "nebula1", + DropLocalBroadcast: false, + DropMulticast: false, + TxQueue: 500, + MTU: 1300, + Routes: nil, + UnsafeRoutes: nil, + }, + Logging: struct { + Level string `yaml:"level"` + Format string `yaml:"format"` + }{ + Level: "info", + Format: "text", + }, + Firewall: struct { + OutboundAction string `yaml:"outbound_action"` + InboundAction string `yaml:"inbound_action"` + Conntrack utils.NebulaConntrackConfig `yaml:"conntrack"` + Outbound []utils.NebulaFirewallRule `yaml:"outbound"` + Inbound []utils.NebulaFirewallRule `yaml:"inbound"` + }{ + OutboundAction: "drop", + InboundAction: "drop", + Conntrack: utils.NebulaConntrackConfig{ + TCPTimeout: "12m", + UDPTimeout: "3m", + DefaultTimeout: "10m", + }, + Outbound: []utils.NebulaFirewallRule { + utils.NebulaFirewallRule { + Host: "any", + Port: "any", + Proto: "any", + }, + }, + Inbound: []utils.NebulaFirewallRule { + utils.NebulaFirewallRule { + Host: "any", + Port: "any", + Proto: "any", + }, + }, + }, + } +} \ No newline at end of file diff --git a/src/httpServer.go b/src/httpServer.go index 1e9c2c9..066a212 100644 --- a/src/httpServer.go +++ b/src/httpServer.go @@ -9,6 +9,7 @@ import ( "github.com/azukaar/cosmos-server/src/docker" "github.com/azukaar/cosmos-server/src/authorizationserver" "github.com/azukaar/cosmos-server/src/market" + "github.com/azukaar/cosmos-server/src/constellation" "github.com/gorilla/mux" "strconv" "time" @@ -331,6 +332,13 @@ func InitServer() *mux.Router { srapi.HandleFunc("/api/background", UploadBackground) srapi.HandleFunc("/api/background/{ext}", GetBackground) + srapi.HandleFunc("/api/constellation/devices", constellation.ConstellationAPIDevices) + srapi.HandleFunc("/api/constellation/restart", constellation.API_Restart) + srapi.HandleFunc("/api/constellation/reset", constellation.API_Reset) + srapi.HandleFunc("/api/constellation/connect", constellation.API_ConnectToExisting) + srapi.HandleFunc("/api/constellation/config", constellation.API_GetConfig) + srapi.HandleFunc("/api/constellation/logs", constellation.API_GetLogs) + srapi.HandleFunc("/api/constellation/block", constellation.DeviceBlock) if(!config.HTTPConfig.AcceptAllInsecureHostname) { srapi.Use(utils.EnsureHostname) diff --git a/src/index.go b/src/index.go index bc1a1b8..c4dc2ab 100644 --- a/src/index.go +++ b/src/index.go @@ -9,6 +9,7 @@ import ( "github.com/azukaar/cosmos-server/src/utils" "github.com/azukaar/cosmos-server/src/authorizationserver" "github.com/azukaar/cosmos-server/src/market" + "github.com/azukaar/cosmos-server/src/constellation" ) func main() { @@ -44,5 +45,9 @@ func main() { authorizationserver.Init() + constellation.InitDNS() + + constellation.Init() + StartServer() } diff --git a/src/market/index.go b/src/market/index.go index 7081b74..ee5d4af 100644 --- a/src/market/index.go +++ b/src/market/index.go @@ -12,7 +12,7 @@ type marketGetResult struct { } func MarketGet(w http.ResponseWriter, req *http.Request) { - if utils.AdminOnly(w, req) != nil { + if utils.LoggedInOnly(w, req) != nil { return } @@ -22,7 +22,6 @@ func MarketGet(w http.ResponseWriter, req *http.Request) { return } - // return the first 10 results of each market marketGetResult := marketGetResult{ All: make(map[string]interface{}), Showcase: []appDefinition{}, diff --git a/src/proxy/routeTo.go b/src/proxy/routeTo.go index e139507..866b0ae 100644 --- a/src/proxy/routeTo.go +++ b/src/proxy/routeTo.go @@ -46,7 +46,7 @@ func joinURLPath(a, b *url.URL) (path, rawpath string) { // NewProxy takes target host and creates a reverse proxy -func NewProxy(targetHost string, AcceptInsecureHTTPSTarget bool, VerboseForwardHeader bool, DisableHeaderHardening bool, CORSOrigin string) (*httputil.ReverseProxy, error) { +func NewProxy(targetHost string, AcceptInsecureHTTPSTarget bool, VerboseForwardHeader bool, DisableHeaderHardening bool, CORSOrigin string, route utils.ProxyRouteConfig) (*httputil.ReverseProxy, error) { url, err := url.Parse(targetHost) if err != nil { return nil, err @@ -76,16 +76,40 @@ func NewProxy(targetHost string, AcceptInsecureHTTPSTarget bool, VerboseForwardH req.Header.Set("X-Forwarded-Ssl", "on") } - if CORSOrigin != "" { - req.Header.Set("X-Forwarded-Host", url.Host) + req.Header.Del("X-Origin-Host") + req.Header.Del("X-Forwarded-Host") + req.Header.Del("X-Forwarded-For") + req.Header.Del("X-Real-Ip") + // hide hostname (dangerous) + // req.Header.Del("Host") + + hostname := utils.GetMainConfig().HTTPConfig.Hostname + if route.Host != "" && route.UseHost { + hostname = route.Host + } + if route.UsePathPrefix { + hostname = hostname + route.PathPrefix } + hostDest := hostname + if route.OverwriteHostHeader != "" { + hostDest = route.OverwriteHostHeader + } + + // hide hostname (dangerous) + // req.Header.Set("Host", url.Host) + // req.Host = url.Host + + req.Header.Set("Host", hostDest) + req.Host = hostDest + if VerboseForwardHeader { - req.Header.Set("X-Origin-Host", url.Host) - req.Header.Set("Host", url.Host) + req.Header.Set("X-Origin-Host", hostDest) + req.Header.Set("X-Forwarded-Host", hostDest) req.Header.Set("X-Forwarded-For", utils.GetClientIP(req)) req.Header.Set("X-Real-IP", utils.GetClientIP(req)) - } + } + } if AcceptInsecureHTTPSTarget && url.Scheme == "https" { @@ -100,8 +124,6 @@ func NewProxy(targetHost string, AcceptInsecureHTTPSTarget bool, VerboseForwardH if CORSOrigin != "" { resp.Header.Del("Access-Control-Allow-Origin") - resp.Header.Del("Access-Control-Allow-Methods") - resp.Header.Del("Access-Control-Allow-Headers") resp.Header.Del("Access-Control-Allow-Credentials") } @@ -126,7 +148,7 @@ func RouteTo(route utils.ProxyRouteConfig) http.Handler { routeType := route.Mode if(routeType == "SERVAPP" || routeType == "PROXY") { - proxy, err := NewProxy(destination, route.AcceptInsecureHTTPSTarget, route.VerboseForwardHeader, route.DisableHeaderHardening, route.CORSOrigin) + proxy, err := NewProxy(destination, route.AcceptInsecureHTTPSTarget, route.VerboseForwardHeader, route.DisableHeaderHardening, route.CORSOrigin, route) if err != nil { utils.Error("Create Route", err) } diff --git a/src/proxy/routerGen.go b/src/proxy/routerGen.go index 3e23364..c12874a 100644 --- a/src/proxy/routerGen.go +++ b/src/proxy/routerGen.go @@ -30,12 +30,12 @@ func tokenMiddleware(enabled bool, adminOnly bool) func(next http.Handler) http. r.Header.Set("x-cosmos-mfa", strconv.Itoa((int)(u.MFAState))) ogcookies := r.Header.Get("Cookie") - cookieRemoveRegex := regexp.MustCompile(`jwttoken=[^;]*;`) + cookieRemoveRegex := regexp.MustCompile(`\s?jwttoken=[^;]*;?\s?`) cookies := cookieRemoveRegex.ReplaceAllString(ogcookies, "") r.Header.Set("Cookie", cookies) // Replace the token with a application speicfic one - r.Header.Set("x-cosmos-token", "1234567890") + //r.Header.Set("x-cosmos-token", "1234567890") if enabled && adminOnly { if errT := utils.AdminOnlyWithRedirect(w, r); errT != nil { @@ -85,6 +85,8 @@ func RouterGen(route utils.ProxyRouteConfig, router *mux.Router, destination htt } } + destination = utils.Restrictions(route.RestrictToConstellation, route.WhitelistInboundIPs)(destination) + destination = SmartShieldMiddleware(route.Name, route.SmartShield)(destination) originCORS := route.CORSOrigin diff --git a/src/user/create.go b/src/user/create.go index 9e6b38b..b2e2f1c 100644 --- a/src/user/create.go +++ b/src/user/create.go @@ -2,12 +2,9 @@ package user import ( "net/http" - // "io" - // "os" "encoding/json" "go.mongodb.org/mongo-driver/mongo" "time" - // "golang.org/x/crypto/bcrypt" "github.com/azukaar/cosmos-server/src/utils" ) diff --git a/src/user/token.go b/src/user/token.go index dd467bb..ad30ab3 100644 --- a/src/user/token.go +++ b/src/user/token.go @@ -5,6 +5,7 @@ import ( "github.com/azukaar/cosmos-server/src/utils" "github.com/golang-jwt/jwt" "errors" + "strconv" "strings" "time" "encoding/json" @@ -189,13 +190,25 @@ func logOutUser(w http.ResponseWriter, req *http.Request) { HttpOnly: true, } + clientCookie := http.Cookie{ + Name: "client-infos", + Value: "{}", + Expires: time.Now().Add(-time.Hour * 24 * 365), + Path: "/", + Secure: utils.IsHTTPS, + HttpOnly: false, + } + if reqHostNoPort == "localhost" || reqHostNoPort == "0.0.0.0" { cookie.Domain = "" + clientCookie.Domain = "" } else { cookie.Domain = "." + reqHostNoPort + clientCookie.Domain = "." + reqHostNoPort } http.SetCookie(w, &cookie) + http.SetCookie(w, &clientCookie) // TODO: logout every other device if asked by increasing passwordcycle } @@ -254,13 +267,24 @@ func SendUserToken(w http.ResponseWriter, req *http.Request, user utils.User, mf HttpOnly: true, } + clientCookie := http.Cookie{ + Name: "client-infos", + Value: user.Nickname + "," + strconv.Itoa(int(user.Role)), + Expires: expiration, + Path: "/", + Secure: utils.IsHTTPS, + HttpOnly: false, + } + utils.Log("UserLogin: Setting cookie for " + reqHostNoPort) if reqHostNoPort == "localhost" || reqHostNoPort == "0.0.0.0" { cookie.Domain = "" + clientCookie.Domain = "" } else { if utils.IsValidHostname(reqHostNoPort) { cookie.Domain = "." + reqHostNoPort + clientCookie.Domain = "." + reqHostNoPort } else { utils.Error("UserLogin: Invalid hostname", nil) utils.HTTPError(w, "User Logging Error", http.StatusInternalServerError, "UL001") @@ -269,4 +293,5 @@ func SendUserToken(w http.ResponseWriter, req *http.Request, user utils.User, mf } http.SetCookie(w, &cookie) + http.SetCookie(w, &clientCookie) } \ No newline at end of file diff --git a/src/utils/certificates.go b/src/utils/certificates.go index 9ea6dd0..5e19a5c 100644 --- a/src/utils/certificates.go +++ b/src/utils/certificates.go @@ -181,20 +181,20 @@ func DoLetsEncrypt() (string, string) { } err = client.Challenge.SetDNS01Provider(provider) - } + } else { + err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", config.HTTPConfig.HTTPPort)) + if err != nil { + Error("LETSENCRYPT_HTTP01", err) + LetsEncryptErrors = append(LetsEncryptErrors, err.Error()) + return "", "" + } - err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", config.HTTPConfig.HTTPPort)) - if err != nil { - Error("LETSENCRYPT_HTTP01", err) - LetsEncryptErrors = append(LetsEncryptErrors, err.Error()) - return "", "" - } - - err = client.Challenge.SetTLSALPN01Provider(tlsalpn01.NewProviderServer("", config.HTTPConfig.HTTPSPort)) - if err != nil { - Error("LETSENCRYPT_TLS01", err) - LetsEncryptErrors = append(LetsEncryptErrors, err.Error()) - return "", "" + err = client.Challenge.SetTLSALPN01Provider(tlsalpn01.NewProviderServer("", config.HTTPConfig.HTTPSPort)) + if err != nil { + Error("LETSENCRYPT_TLS01", err) + LetsEncryptErrors = append(LetsEncryptErrors, err.Error()) + return "", "" + } } // New users will need to register diff --git a/src/utils/middleware.go b/src/utils/middleware.go index 406174c..e75be2b 100644 --- a/src/utils/middleware.go +++ b/src/utils/middleware.go @@ -82,8 +82,6 @@ func CORSHeader(origin string) func(next http.Handler) http.Handler { if origin != "" { w.Header().Set("Access-Control-Allow-Origin", origin) - w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") - w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") w.Header().Set("Access-Control-Allow-Credentials", "true") } @@ -260,4 +258,60 @@ func IsValidHostname(hostname string) bool { } return false +} + +func IPInRange(ipStr, cidrStr string) (bool, error) { + _, cidrNet, err := net.ParseCIDR(cidrStr) + if err != nil { + return false, fmt.Errorf("parse CIDR range: %w", err) + } + + ip := net.ParseIP(ipStr) + if ip == nil { + return false, fmt.Errorf("parse IP: invalid IP address") + } + + return cidrNet.Contains(ip), nil +} + +func Restrictions(RestrictToConstellation bool, WhitelistInboundIPs []string) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + ip, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + http.Error(w, "Invalid request", http.StatusBadRequest) + return + } + + isUsingWhiteList := len(WhitelistInboundIPs) > 0 + + isInWhitelist := false + isInConstellation := strings.HasPrefix(ip, "192.168.201.") || strings.HasPrefix(ip, "192.168.202.") + + for _, ipRange := range WhitelistInboundIPs { + if strings.Contains(ipRange, "/") { + if ok, _ := IPInRange(ip, ipRange); ok { + isInWhitelist = true + } + } else { + if ip == ipRange { + isInWhitelist = true + } + } + } + + isInConstellationPassing := !RestrictToConstellation || isInConstellation + isWhitelistPassing := !isUsingWhiteList || isInWhitelist + + // check if the request is coming from the constellation IP range 192.168.201.0/24 + if (!isInConstellationPassing && !isWhitelistPassing) { + Log("Request from " + ip + " is blocked because of restrictions isInConstellationPassing: " + fmt.Sprintf("%v", isInConstellationPassing) + " and isWhitelistPassing: " + fmt.Sprintf("%v", isWhitelistPassing)) + http.Error(w, "Access denied", http.StatusForbidden) + return + } + + next.ServeHTTP(w, r) + }) + } } \ No newline at end of file diff --git a/src/utils/types.go b/src/utils/types.go index 1f6d9f3..ea90806 100644 --- a/src/utils/types.go +++ b/src/utils/types.go @@ -90,6 +90,7 @@ type Config struct { MarketConfig MarketConfig HomepageConfig HomepageConfig ThemeConfig ThemeConfig + ConstellationConfig ConstellationConfig } type HomepageConfig struct { @@ -180,6 +181,9 @@ type ProxyRouteConfig struct { DisableHeaderHardening bool VerboseForwardHeader bool AddionalFilters []AddionalFiltersConfig + RestrictToConstellation bool + OverwriteHostHeader string + WhitelistInboundIPs []string } type EmailConfig struct { @@ -205,4 +209,115 @@ type MarketConfig struct { type MarketSource struct { Name string Url string -} \ No newline at end of file +} + +type ConstellationConfig struct { + Enabled bool + SlaveMode bool + PrivateNode bool + DNSDisabled bool + DNSPort string + DNSFallback string + DNSBlockBlacklist bool + DNSAdditionalBlocklists []string + CustomDNSEntries []ConstellationDNSEntry + NebulaConfig NebulaConfig + ConstellationHostname string +} + +type ConstellationDNSEntry struct { + Type string + Key string + Value string +} +type ConstellationDevice struct { + Nickname string `json:"nickname"` + DeviceName string `json:"deviceName"` + PublicKey string `json:"publicKey"` + IP string `json:"ip"` + IsLighthouse bool `json:"isLighthouse"` + IsRelay bool `json:"isRelay"` + PublicHostname string `json:"publicHostname"` + Port string `json:"port"` + Blocked bool `json:"blocked"` + Fingerprint string `json:"fingerprint"` + APIKey string `json:"-"` +} + +type NebulaFirewallRule struct { + Port string `yaml:"port"` + Proto string `yaml:"proto"` + Host string `yaml:"host"` + Groups []string `yaml:"groups,omitempty"omitempty"` +} + +type NebulaConntrackConfig struct { + TCPTimeout string `yaml:"tcp_timeout"` + UDPTimeout string `yaml:"udp_timeout"` + DefaultTimeout string `yaml:"default_timeout"` +} + +type NebulaConfig struct { + PKI struct { + CA string `yaml:"ca"` + Cert string `yaml:"cert"` + Key string `yaml:"key"` + Blocklist []string `yaml:"blocklist"` + } `yaml:"pki"` + + StaticHostMap map[string][]string `yaml:"static_host_map"` + + Lighthouse struct { + AMLighthouse bool `yaml:"am_lighthouse"` + Interval int `yaml:"interval"` + Hosts []string `yaml:"hosts"` + } `yaml:"lighthouse"` + + Listen struct { + Host string `yaml:"host"` + Port int `yaml:"port"` + } `yaml:"listen"` + + Punchy struct { + Punch bool `yaml:"punch"` + Respond bool `yaml:"respond"` + } `yaml:"punchy"` + + Relay struct { + AMRelay bool `yaml:"am_relay"` + UseRelays bool `yaml:"use_relays"` + Relays []string `yaml:"relays"` + } `yaml:"relay"` + + TUN struct { + Disabled bool `yaml:"disabled"` + Dev string `yaml:"dev"` + DropLocalBroadcast bool `yaml:"drop_local_broadcast"` + DropMulticast bool `yaml:"drop_multicast"` + TxQueue int `yaml:"tx_queue"` + MTU int `yaml:"mtu"` + Routes []string `yaml:"routes"` + UnsafeRoutes []string `yaml:"unsafe_routes"` + } `yaml:"tun"` + + Logging struct { + Level string `yaml:"level"` + Format string `yaml:"format"` + } `yaml:"logging"` + + Firewall struct { + OutboundAction string `yaml:"outbound_action"` + InboundAction string `yaml:"inbound_action"` + Conntrack NebulaConntrackConfig `yaml:"conntrack"` + Outbound []NebulaFirewallRule `yaml:"outbound"` + Inbound []NebulaFirewallRule `yaml:"inbound"` + } `yaml:"firewall"` +} + +type Device struct { + DeviceName string `json:"deviceName",validate:"required,min=3,max=32,alphanum"` + Nickname string `json:"nickname",validate:"required,min=3,max=32,alphanum"` + PublicKey string `json:"publicKey",omitempty` + PrivateKey string `json:"privateKey",omitempty` + IP string `json:"ip",validate:"required,ipv4"` +} diff --git a/src/utils/utils.go b/src/utils/utils.go index 6177a0c..cf5b0b3 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -37,6 +37,8 @@ var ReBootstrapContainer func(string) error var LetsEncryptErrors = []string{} +var CONFIGFOLDER = "/config/" + var DefaultConfig = Config{ LoggingLevel: "INFO", NewInstall: true, @@ -60,6 +62,17 @@ var DefaultConfig = Config{ Sources: []MarketSource{ }, }, + ConstellationConfig: ConstellationConfig{ + Enabled: false, + DNSDisabled: false, + DNSFallback: "8.8.8.8:53", + DNSAdditionalBlocklists: []string{ + "https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt", + "https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt", + "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts", + "https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-only/hosts", + }, + }, } func FileExists(path string) bool { @@ -193,10 +206,23 @@ func LoadBaseMainConfig(config Config) { if os.Getenv("COSMOS_SERVER_COUNTRY") != "" { MainConfig.ServerCountry = os.Getenv("COSMOS_SERVER_COUNTRY") } + if os.Getenv("COSMOS_CONFIG_FOLDER") != "" { + Log("Overwriting config folder with " + os.Getenv("COSMOS_CONFIG_FOLDER")) + CONFIGFOLDER = os.Getenv("COSMOS_CONFIG_FOLDER") + } if MainConfig.DockerConfig.DefaultDataPath == "" { MainConfig.DockerConfig.DefaultDataPath = "/usr" } + + if MainConfig.ConstellationConfig.ConstellationHostname == "" { + // if hostname is a domain add vpn. suffix otherwise use hostname + if IsDomain(MainConfig.HTTPConfig.Hostname) { + MainConfig.ConstellationConfig.ConstellationHostname = "vpn." + MainConfig.HTTPConfig.Hostname + } else { + MainConfig.ConstellationConfig.ConstellationHostname = MainConfig.HTTPConfig.Hostname + } + } } func GetMainConfig() Config { @@ -219,7 +245,7 @@ func GetConfigFileName() string { configFile := os.Getenv("CONFIG_FILE") if configFile == "" { - configFile = "/config/cosmos.config.json" + configFile = CONFIGFOLDER + "cosmos.config.json" } return configFile @@ -539,10 +565,33 @@ func GetNetworkUsage() NetworkStatus { return NetworkStatus{} } +func DownloadFile(url string) (string, error) { + resp, err := http.Get(url) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + return string(body), nil +} + func GetClientIP(req *http.Request) string { /*ip := req.Header.Get("X-Forwarded-For") if ip == "" { ip = req.RemoteAddr }*/ return req.RemoteAddr +} + +func IsDomain(domain string) bool { + // contains . and at least a letter and no special characters invalid in a domain + if strings.Contains(domain, ".") && strings.ContainsAny(domain, "abcdefghijklmnopqrstuvwxyz") && !strings.ContainsAny(domain, " !@#$%^&*()+=[]{}\\|;:'\",/<>?") { + return true + } + return false } \ No newline at end of file