diff --git a/.github/workflows/github-actions-ec2.yaml b/.github/workflows/github-actions-ec2.yaml index 1e97ba6..da6c6de 100644 --- a/.github/workflows/github-actions-ec2.yaml +++ b/.github/workflows/github-actions-ec2.yaml @@ -19,7 +19,7 @@ jobs: username: ${{ secrets.USERNAME }} key: ${{ secrets.EC2_SSH_KEY }} script: | - cd ~/project-domain-forge/domain-forge/docker + cd ~/domain-forge/docker docker compose down git pull origin master docker compose up -d --build diff --git a/docs/admin/README.md b/docs/admin/README.md index 577eaae..046e45d 100644 --- a/docs/admin/README.md +++ b/docs/admin/README.md @@ -26,7 +26,7 @@ This step involves the configuration of three `.env` files: SENTRY_DSN=... ``` - Frontend env: - As suggested in the `.env.sample` present at the `src/frontend` directory, create a file named `.env` and copy the contents as shown, replacing *"..."* with the respective values for your registered github oauth application's **VITE_APP_GITHUB_OAUTH_CLIENT_ID** and **VITE_APP_GITHUB_OAUTH_CLIENT_SECRET**. For the **VITE_APP_GITHUB_OAUTH_REDIRECT_URL** enter the public url of the application's `/login` route. (Example: `http://df.mdgspace.org/login`). Also, add the port at which your backend is running in place of *"XXXX"*. + As suggested in the `.env.sample` present at the `src/frontend` directory, create a file named `.env` and copy the contents as shown, replacing *"..."* with the respective values for your registered github oauth application's **VITE_APP_GITHUB_OAUTH_CLIENT_ID** and **VITE_APP_GITHUB_OAUTH_CLIENT_SECRET**. For the **VITE_APP_GITHUB_OAUTH_REDIRECT_URL** enter the public url of the application's `/login` route. (Example: `https://domains.mdgspace.org/login`). Also, add the port at which your backend is running in place of *"XXXX"*. ``` VITE_APP_GITHUB_OAUTH_CLIENT_ID=... VITE_APP_GITHUB_OAUTH_CLIENT_SECRET=... @@ -61,6 +61,6 @@ Refer to [this](https://www.digitalocean.com/community/tutorials/how-to-set-up-n ### 6. Adding the DNS Records and Issue SSL Certificates -Refer to [this](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/) to add DNS records for *df.yourorgname.com* and also a wildcard DNS record for **.df.yourorgname.com* +Refer to [this](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/) to add DNS records for *domains.yourorgname.com* and also a wildcard DNS record for **.domains.yourorgname.com* -You can use [letsencrypt](https://letsencrypt.org/) to issue SSL certificates for *df.yourorgname.com* and a wildcard SSL certificate for **.df.yourorgname.com*. +You can use [letsencrypt](https://letsencrypt.org/) to issue SSL certificates for *domains.yourorgname.com* and a wildcard SSL certificate for **.domains.yourorgname.com*. diff --git a/src/backend/.env.sample b/src/backend/.env.sample index 3070d10..012341a 100644 --- a/src/backend/.env.sample +++ b/src/backend/.env.sample @@ -5,4 +5,6 @@ GITLAB_OAUTH_CLIENT_SECRET=... MONGO_API_KEY=... MONGO_APP_ID=... SENTRY_DSN=... -FRONTEND=... \ No newline at end of file +FRONTEND=... +ADMIN_LIST=admin1|admin2 +MEMORY_LIMIT=500m \ No newline at end of file diff --git a/src/backend/db.ts b/src/backend/db.ts index c5b4814..a50e02d 100644 --- a/src/backend/db.ts +++ b/src/backend/db.ts @@ -51,12 +51,13 @@ async function checkUser(accessToken: string, provider: string) { } // Get all content maps corresponding to user -async function getMaps(author: string) { +async function getMaps(author: string, ADMIN_LIST: string[]) { + const filter = ADMIN_LIST?.includes(author) ? {} : { "author": author }; const query = { collection: "content_maps", database: DATABASE, dataSource: DATA_SOURCE, - filter: { "author": author }, + filter: filter, }; options.body = JSON.stringify(query); const resp = await fetch(MONGO_URLs.find.toString(), options); @@ -96,12 +97,16 @@ async function addMaps(document: DfContentMap) { } // Delete content maps -async function deleteMaps(document: DfContentMap) { +async function deleteMaps(document: DfContentMap, ADMIN_LIST: string[]) { + const filter = JSON.parse(JSON.stringify(document)); + if (ADMIN_LIST.includes(document.author)) { + delete filter.author; + } const query = { collection: "content_maps", database: DATABASE, dataSource: DATA_SOURCE, - filter: document, + filter: filter, }; options.body = JSON.stringify(query); diff --git a/src/backend/main.ts b/src/backend/main.ts index 5dfc1ea..eca17ba 100644 --- a/src/backend/main.ts +++ b/src/backend/main.ts @@ -3,6 +3,8 @@ import { addScript, deleteScript } from "./scripts.ts"; import { checkJWT } from "./utils/jwt.ts"; import { addMaps, deleteMaps, getMaps } from "./db.ts"; +const ADMIN_LIST = Deno.env.get("ADMIN_LIST")?.split("|"); + async function getSubdomains(ctx: Context) { const author = ctx.request.url.searchParams.get("user"); const token = ctx.request.url.searchParams.get("token"); @@ -10,7 +12,7 @@ async function getSubdomains(ctx: Context) { if (author != await checkJWT(provider!, token!)) { ctx.throw(401); } - const data = await getMaps(author); + const data = await getMaps(author, ADMIN_LIST!); ctx.response.headers.set("Access-Control-Allow-Origin", "*"); ctx.response.body = data.documents; } @@ -33,9 +35,11 @@ async function addSubdomain(ctx: Context) { delete document.provider; delete document.port; delete document.build_cmds; + delete document.dockerfile_present; delete document.stack; delete document.env_content; delete document.static_content; + if (document.author != await checkJWT(provider, token)) { ctx.throw(401); } @@ -47,6 +51,7 @@ async function addSubdomain(ctx: Context) { document, copy.env_content, copy.static_content, + copy.dockerfile_present, copy.stack, copy.port, copy.build_cmds, @@ -80,7 +85,7 @@ async function deleteSubdomain(ctx: Context) { if (author != await checkJWT(provider, token)) { ctx.throw(401); } - const data = await deleteMaps(document); + const data = await deleteMaps(document, ADMIN_LIST!); if (data.deletedCount) { deleteScript(document); Sentry.captureMessage( diff --git a/src/backend/scripts.ts b/src/backend/scripts.ts index 4bf4fdb..fcdb711 100644 --- a/src/backend/scripts.ts +++ b/src/backend/scripts.ts @@ -2,10 +2,13 @@ import { exec } from "./dependencies.ts"; import dockerize from "./utils/container.ts"; import DfContentMap from "./types/maps_interface.ts"; +const MEMORY_LIMIT = Deno.env.get("MEMORY_LIMIT"); + async function addScript( document: DfContentMap, env_content: string, static_content: string, + dockerfile_present:string, stack: string, port: string, build_cmds: string, @@ -21,15 +24,23 @@ async function addScript( } else if (document.resource_type === "GITHUB" && static_content == "Yes") { Deno.writeTextFile(`/hostpipe/.env`, env_content); await exec( - `bash -c "echo 'bash ../../src/backend/shell_scripts/container.sh -s ${document.subdomain} ${document.resource}' > /hostpipe/pipe"`, + `bash -c "echo 'bash ../../src/backend/shell_scripts/container.sh -s ${document.subdomain} ${document.resource} 80 ${MEMORY_LIMIT}' > /hostpipe/pipe"`, ); } else if (document.resource_type === "GITHUB" && static_content == "No") { - const dockerfile = dockerize(stack, port, build_cmds); + if(dockerfile_present === 'No'){ + const dockerfile = dockerize(stack, port, build_cmds); Deno.writeTextFile(`/hostpipe/Dockerfile`, dockerfile); Deno.writeTextFile(`/hostpipe/.env`, env_content); await exec( - `bash -c "echo 'bash ../../src/backend/shell_scripts/container.sh -g ${document.subdomain} ${document.resource} ${port}' > /hostpipe/pipe"`, + `bash -c "echo 'bash ../../src/backend/shell_scripts/container.sh -g ${document.subdomain} ${document.resource} ${port} ${MEMORY_LIMIT}' > /hostpipe/pipe"`, ); + }else if(dockerfile_present === 'Yes'){ + + await exec( + `bash -c "echo 'bash ../../src/backend/shell_scripts/container.sh -d ${document.subdomain} ${document.resource} ${port} ${MEMORY_LIMIT}' > /hostpipe/pipe"`, + ); + } + } } diff --git a/src/backend/shell_scripts/automate.sh b/src/backend/shell_scripts/automate.sh index 9303d9c..03c7bd2 100644 --- a/src/backend/shell_scripts/automate.sh +++ b/src/backend/shell_scripts/automate.sh @@ -24,7 +24,7 @@ if [ "$arg1" = "-u" ]; then listen 80; listen [::]:80; listen 443 ssl; - listen [::]:443 ssl; + listen [::]:443 ssl; server_name $arg3; location / { @@ -32,8 +32,8 @@ if [ "$arg1" = "-u" ]; then } charset utf-8; client_max_body_size 20M; - ssl_certificate /etc/letsencrypt/live/df.mdgspace.org-0001/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/df.mdgspace.org-0001/privkey.pem; + ssl_certificate /etc/letsencrypt/live/domains.mdgspace.org-0002/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/domains.mdgspace.org-0002/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; }" > /etc/nginx/sites-available/$arg3.conf; @@ -62,8 +62,8 @@ elif [ "$arg1" = "-p" ]; then } charset utf-8; client_max_body_size 20M; - ssl_certificate /etc/letsencrypt/live/df.mdgspace.org-0001/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/df.mdgspace.org-0001/privkey.pem; + ssl_certificate /etc/letsencrypt/live/domains.mdgspace.org-0002/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/domains.mdgspace.org-0002/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; }" > /etc/nginx/sites-available/$arg3.conf; diff --git a/src/backend/shell_scripts/container.sh b/src/backend/shell_scripts/container.sh old mode 100644 new mode 100755 index 730460a..68cdc73 --- a/src/backend/shell_scripts/container.sh +++ b/src/backend/shell_scripts/container.sh @@ -3,7 +3,8 @@ PORT_MAX=8099 flag=$1 name=$2 resource=$3 -exp_port=$4 +exp_port=$4 +max_mem=$5 available_ports=() @@ -15,23 +16,29 @@ done echo "Available ports: ${available_ports[56]}" AVAILABLE=0 +echo "Creating subdomain $name" +git clone $resource $name +sudo cp .env $name/ +cd $name + if [ $flag = "-g" ]; then - echo "Creating subdomain $name" - git clone $resource $name - sudo cp Dockerfile $name/ - sudo cp .env $name/ - cd $name - sudo docker build -t $name . - echo ${available_ports[$AVAILABLE]}; - sudo docker run --name=$name -d -p ${available_ports[$AVAILABLE]}:$exp_port $2 - cd .. - sudo rm -rf $name - sudo rm Dockerfile - sudo rm .env + sudo cp ../Dockerfile ./ +elif [ $flag = "-s" ]; then + sudo echo " + FROM nginx:alpine + COPY . /usr/share/nginx/html + " > Dockerfile +fi - sudo touch /etc/nginx/sites-available/$2.conf - sudo chmod 666 /etc/nginx/sites-available/$2.conf - sudo echo "# Virtual Host configuration for example.com +sudo docker build -t $name . +sudo docker run --memory=$max_mem --name=$name -d -p ${available_ports[$AVAILABLE]}:$exp_port $2 +cd .. +sudo rm -rf $name +sudo rm Dockerfile +sudo rm .env +sudo touch /etc/nginx/sites-available/$2.conf +sudo chmod 666 /etc/nginx/sites-available/$2.conf +sudo echo "# Virtual Host configuration for $2 server { listen 80; listen [::]:80; @@ -48,55 +55,10 @@ if [ $flag = "-g" ]; then } charset utf-8; client_max_body_size 20M; - ssl_certificate /etc/letsencrypt/live/df.mdgspace.org-0001/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/df.mdgspace.org-0001/privkey.pem; + ssl_certificate /etc/letsencrypt/live/domains.mdgspace.org-0002/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/domains.mdgspace.org-0002/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; }" > /etc/nginx/sites-available/$2.conf - sudo ln -s /etc/nginx/sites-available/$2.conf /etc/nginx/sites-enabled/$2.conf - sudo systemctl reload nginx - -else - echo "Creating subdomain $name" - git clone $resource $name - sudo cp .env $name/ - cd $name - sudo echo " - FROM nginx:alpine - COPY . /usr/share/nginx/html - " > Dockerfile - sudo docker build -t $name . - sudo docker run --name=$name -d -p ${available_ports[$AVAILABLE]}:80 $name - cd .. - sudo rm .env - sudo rm -rf $name - sudo touch /etc/nginx/sites-available/$2.conf - sudo chmod 666 /etc/nginx/sites-available/$2.conf - sudo echo "# Virtual Host configuration for example.com - server { - listen 80; - listen [::]:80; - listen 443 ssl; - listen [::]:443 ssl; - server_name $2; - location / { - proxy_pass http://localhost:${available_ports[$AVAILABLE]}; - proxy_http_version 1.1; - proxy_set_header Upgrade \$http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header Host \$host; - proxy_cache_bypass \$http_upgrade; - } - charset utf-8; - client_max_body_size 20M; - ssl_certificate /etc/letsencrypt/live/df.mdgspace.org-0001/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/df.mdgspace.org-0001/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; - }" > /etc/nginx/sites-available/$2.conf; - sudo ln -s /etc/nginx/sites-available/$2.conf /etc/nginx/sites-enabled/$2.conf; - sudo systemctl reload nginx; -fi - - - +sudo ln -s /etc/nginx/sites-available/$2.conf /etc/nginx/sites-enabled/$2.conf +sudo systemctl reload nginx diff --git a/src/backend/utils/container.ts b/src/backend/utils/container.ts index f3b2d04..1e20d82 100644 --- a/src/backend/utils/container.ts +++ b/src/backend/utils/container.ts @@ -4,6 +4,7 @@ export default function dockerize( build_cmds: string, ) { let dockerfile = ""; + build_cmds = build_cmds.replace(/\r?\n$/, ''); const run_cmd = build_cmds.split("\n"); const execute_cmd = "CMD " + JSON.stringify(run_cmd.pop()?.split(" ")); const build_cmds_mapped = run_cmd.map((elem) => { @@ -11,12 +12,12 @@ export default function dockerize( }).join("\n"); if (stack == "Python") { dockerfile = - "FROM python:3.11 \nWORKDIR /app \nCOPY requirements.txt . \nRUN pip install --no-cache-dir -r requirements.txt \nCOPY . ." + + "FROM python:latest \nWORKDIR /app \nCOPY requirements.txt . \nRUN pip install --no-cache-dir -r requirements.txt \nCOPY . ." + build_cmds_mapped + `\nEXPOSE ${port}\n` + execute_cmd; } else if (stack == "NodeJS") { dockerfile = - "FROM node:latest \n WORKDIR /app \n COPY ./package*.json . \n RUN npm install \n COPY . ." + - build_cmds_mapped + `\n EXPOSE ${port} \n` + execute_cmd; + "FROM node:latest \nWORKDIR /app \nCOPY ./package*.json . \nRUN npm install \nCOPY . ." + + build_cmds_mapped + `\nEXPOSE ${port} \n` + execute_cmd; } return dockerfile.toString(); } diff --git a/src/frontend/.env.sample b/src/frontend/.env.sample index 5e4e420..7480e51 100644 --- a/src/frontend/.env.sample +++ b/src/frontend/.env.sample @@ -4,4 +4,5 @@ VITE_APP_GITHUB_OAUTH_REDIRECT_URL=.../login VITE_APP_GITLAB_OAUTH_CLIENT_ID=... VITE_APP_GITLAB_OAUTH_CLIENT_SECRET=... VITE_APP_GITLAB_OAUTH_REDIRECT_URL=.../login -VITE_APP_BACKEND=... \ No newline at end of file +VITE_APP_BACKEND=... +VITE_APP_DOMAIN=your-domain.com \ No newline at end of file diff --git a/src/frontend/src/components/modal.vue b/src/frontend/src/components/modal.vue index e329174..70f8f4f 100644 --- a/src/frontend/src/components/modal.vue +++ b/src/frontend/src/components/modal.vue @@ -1,3 +1,6 @@ +