├── backend ├── logs │ ├── debug.log │ ├── main.log │ ├── add_url.log │ ├── db_error.log │ └── url_stats.log ├── chi_url │ ├── __init__.py │ ├── cache_backend │ │ └── __init__.py │ ├── config.py │ ├── errors.py │ ├── delete_url.py │ ├── main.py │ ├── db.py │ ├── url_routing.py │ ├── url_stats.py │ ├── users.py │ ├── add_url.py │ ├── email_verification.py │ ├── session_token.py │ └── email_template.py ├── .gitignore ├── .dockerignore ├── Dockerfile └── requirements.txt ├── cassandra ├── .dockerignore ├── entrypoint.sh ├── node1 │ └── cassandra │ │ ├── triggers │ │ └── README.txt │ │ ├── cassandra-jaas.config │ │ ├── README.txt │ │ ├── jvm8-clients.options │ │ ├── jvm-clients.options │ │ ├── logback-tools.xml │ │ ├── jvm11-clients.options │ │ ├── cassandra-topology.properties │ │ ├── metrics-reporter-config-sample.yaml │ │ ├── cassandra-rackdc.properties │ │ ├── commitlog_archiving.properties │ │ ├── jvm8-server.options │ │ ├── hotspot_compiler │ │ ├── jvm11-server.options │ │ ├── logback.xml │ │ ├── cassandra.yaml │ │ ├── cqlshrc.sample │ │ ├── jvm-server.options │ │ └── cassandra-env.sh └── init_keyspace.cql ├── recreate-backend.sh ├── static ├── icon.png └── architecture.png ├── frontend ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── src │ ├── Mycomponents │ │ └── pages │ │ │ ├── components │ │ │ ├── footer.css │ │ │ ├── footer.js │ │ │ └── nav.js │ │ │ ├── Homepages │ │ │ ├── home.css │ │ │ ├── errorPage.js │ │ │ ├── main.js │ │ │ ├── home.js │ │ │ └── page.js │ │ │ ├── userpages │ │ │ ├── userpage.css │ │ │ └── userpage.js │ │ │ └── signuppages │ │ │ ├── verifymail.js │ │ │ ├── login.js │ │ │ └── signup.js │ ├── index.js │ ├── index.css │ ├── proxysetup.js │ └── App.js ├── Dockerfile ├── .gitignore ├── package.json └── .dockerignore ├── recreate-frontend.sh ├── local ├── .env ├── requirements.txt ├── local_nginx │ └── nginx.conf └── docker-compose.yaml ├── .github └── workflows │ ├── greetings.yml │ └── codeql-analysis.yml ├── setup.sh ├── LICENSE ├── nginx └── nginx.conf ├── Readme.MD ├── docker-compose.yaml └── init-letsencrypt.sh /backend/logs/debug.log: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/logs/main.log: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/chi_url/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/logs/add_url.log: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/logs/db_error.log: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/logs/url_stats.log: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cassandra/.dockerignore: -------------------------------------------------------------------------------- 1 | node1 2 | node2 3 | node3 4 | .dockerignore 5 | Dockerfile -------------------------------------------------------------------------------- /recreate-backend.sh: -------------------------------------------------------------------------------- 1 | sudo docker-compose up --build --force-recreate backend nginx -------------------------------------------------------------------------------- /static/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cosmicoppai/chi_url/HEAD/static/icon.png -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | ../.idea 2 | chi_url/.env 3 | env 4 | chi_url/__pycache__ 5 | chi_url/test.py 6 | -------------------------------------------------------------------------------- /backend/chi_url/cache_backend/__init__.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | cache = redis.Redis(host='redis') 4 | -------------------------------------------------------------------------------- /cassandra/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cqlsh -f init_keyspace.cql -u cassandra -p cassandra -------------------------------------------------------------------------------- /static/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cosmicoppai/chi_url/HEAD/static/architecture.png -------------------------------------------------------------------------------- /frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /cassandra/node1/cassandra/triggers/README.txt: -------------------------------------------------------------------------------- 1 | Place triggers to be loaded in this directory, as jar files. 2 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cosmicoppai/chi_url/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/src/Mycomponents/pages/components/footer.css: -------------------------------------------------------------------------------- 1 | .cont{ 2 | background-color: "#212529"; 3 | margin-top:"-100px"; 4 | 5 | } -------------------------------------------------------------------------------- /recreate-frontend.sh: -------------------------------------------------------------------------------- 1 | sudo docker-compose stop 2 | 3 | sudo docker volume rm chi_url_react_build 4 | 5 | sudo docker-compose up --build --force-recreate frontend nginx -------------------------------------------------------------------------------- /backend/.dockerignore: -------------------------------------------------------------------------------- 1 | .github 2 | tests 3 | env 4 | .gitignore 5 | .dockerignore 6 | .env 7 | .idea 8 | chi_url/.env 9 | chi_url/__pycache__ 10 | chi_url/test.py 11 | Readme.MD -------------------------------------------------------------------------------- /cassandra/node1/cassandra/cassandra-jaas.config: -------------------------------------------------------------------------------- 1 | // Delegates authentication to Cassandra's configured IAuthenticator 2 | CassandraLogin { 3 | org.apache.cassandra.auth.CassandraLoginModule REQUIRED; 4 | }; 5 | -------------------------------------------------------------------------------- /frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16.8.0-slim 2 | 3 | WORKDIR /frontend 4 | 5 | COPY package.json ./ 6 | 7 | RUN npm config set registry https://registry.npmjs.com/ 8 | 9 | RUN npm install 10 | 11 | COPY . ./ 12 | 13 | RUN npm run build -------------------------------------------------------------------------------- /local/.env: -------------------------------------------------------------------------------- 1 | DB_USERNAME=cassandra 2 | DB_PASSWORD=cassandra 3 | KEYSPACE=chi_url 4 | SECRET_KEY=secret-key 5 | ALGORITHM=HS256 6 | 7 | EMAIL=email-id 8 | EMAIL_PASSWORD=password 9 | 10 | ORIGIN=http://frontend:3000 11 | ORIGIN2=http://localhost 12 | HOST=http://localhost -------------------------------------------------------------------------------- /frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import "bootstrap/dist/css/bootstrap.min.css"; 6 | import "bootstrap/dist/js/bootstrap.js"; 7 | ReactDOM.render(, document.getElementById('root')); -------------------------------------------------------------------------------- /frontend/src/Mycomponents/pages/Homepages/home.css: -------------------------------------------------------------------------------- 1 | #mystyle{ 2 | margin-top: -420px; 3 | } 4 | #style{ 5 | font-family: "fell, Georgia, Cambria, Times New Roman, Times, serif"; 6 | } 7 | @media only screen and (max-width: 600px) { 8 | #mystyle{ 9 | margin-top: -500px; 10 | } 11 | } -------------------------------------------------------------------------------- /cassandra/node1/cassandra/README.txt: -------------------------------------------------------------------------------- 1 | Required configuration files 2 | ============================ 3 | 4 | cassandra.yaml: main Cassandra configuration file 5 | logback.xml: logback configuration file for Cassandra server 6 | 7 | 8 | Optional configuration files 9 | ============================ 10 | 11 | cassandra-topology.properties: used by PropertyFileSnitch 12 | 13 | 14 | -------------------------------------------------------------------------------- /frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/Mycomponents/pages/Homepages/errorPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const ErrorPage = () => { 4 | return ( 5 |
6 | 7 |
8 | ) 9 | } 10 | 11 | export default ErrorPage 12 | -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | name: Greetings 2 | 3 | on: [pull_request, issues] 4 | 5 | jobs: 6 | greeting: 7 | runs-on: ubuntu-latest 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | steps: 12 | - uses: actions/first-interaction@v1 13 | with: 14 | repo-token: ${{ secrets.GITHUB_TOKEN }} 15 | issue-message: 'Thanks for the contribution' 16 | pr-message: 'Thanks!' 17 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules/ 5 | /node_modules 6 | /.pnp 7 | .pnp.js 8 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | -------------------------------------------------------------------------------- /cassandra/node1/cassandra/jvm8-clients.options: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # jvm8-clients.options # 3 | # # 4 | # See jvm-clients.options. This file is specific for Java 8 and newer. # 5 | ########################################################################### 6 | 7 | # intentionally left empty 8 | 9 | # The newline in the end of file is intentional 10 | -------------------------------------------------------------------------------- /cassandra/node1/cassandra/jvm-clients.options: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # jvm-clients.options # 3 | # # 4 | # See jvm8-clients.options and jvm11-clients.options for Java version # 5 | # specific options. # 6 | ########################################################################### 7 | 8 | # intentionally left empty 9 | 10 | # The newline in the end of file is intentional 11 | -------------------------------------------------------------------------------- /frontend/src/Mycomponents/pages/Homepages/main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | 4 | export const Main = () => { 5 | const myStyle = { 6 | width: '80 %', 7 | height: '400px', 8 | borderRadius: '21px 21px 0 0' 9 | } 10 | 11 | return ( 12 |
13 |
14 |

15 |
16 |
17 |
18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /backend/chi_url/config.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseSettings 2 | 3 | 4 | class Settings(BaseSettings): 5 | db_username: str 6 | db_password: str 7 | keyspace: str 8 | 9 | class Config: 10 | env_file = '.env' 11 | env_file_encoding = 'utf-8' 12 | 13 | 14 | class JWT_Settings(BaseSettings): 15 | secret_key: str 16 | algorithm: str 17 | 18 | class Config: 19 | env_file = ".env" 20 | 21 | 22 | class EmailSettings(BaseSettings): 23 | email: str 24 | email_password: str 25 | 26 | class Config: 27 | env_file = '.env' 28 | 29 | 30 | class OriginSettings(BaseSettings): 31 | origin: str 32 | origin2: str 33 | origin3: str 34 | host: str 35 | 36 | class Config: 37 | env_file = '.env' 38 | -------------------------------------------------------------------------------- /backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9.4-slim 2 | 3 | LABEL MAINTAINER="CosmicOppai" 4 | LABEL Description="Highly Scalable URL Shortener written using FASTAPI, REACT and Cassandra" 5 | 6 | COPY requirements.txt requirements.txt 7 | 8 | RUN pip install -r requirements.txt 9 | 10 | COPY chi_url backend/chi_url 11 | 12 | COPY logs backend/logs 13 | 14 | WORKDIR backend/chi_url 15 | 16 | ENV DB_USERNAME=${DB_USERNAME} 17 | ENV DB_PASSWORD=${DB_PASSWORD} 18 | ENV KEYSPACE=${KEYSPACE} 19 | ENV SECRET_KEY=${SECRET_KEY} 20 | ENV ALGORITHM=${ALGORITHM} 21 | ENV EMAIL=${EMAIL} 22 | ENV EMAIL_PASSWORD=${EMAIL_PASSWORD} 23 | ENV ORIGIN=${ORIGIN} 24 | ENV ORIGIN2=${ORIGIN2} 25 | 26 | EXPOSE 8000 27 | 28 | CMD ["gunicorn", "main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "--bind","0.0.0.0:8000"] -------------------------------------------------------------------------------- /backend/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | asgiref==3.5.2 3 | async-timeout==4.0.2 4 | bcrypt==3.2.2 5 | cassandra-driver==3.25.0 6 | cffi==1.15.0 7 | click==8.1.3 8 | colorama==0.4.4 9 | cryptography==37.0.2 10 | Deprecated==1.2.13 11 | dnspython==2.2.1 12 | ecdsa==0.17.0 13 | email-validator==1.2.1 14 | fastapi==0.78.0 15 | geomet==0.2.1.post1 16 | gunicorn==20.1.0 17 | h11==0.13.0 18 | httptools==0.4.0 19 | idna==3.3 20 | packaging==21.3 21 | passlib==1.7.4 22 | pyasn1==0.4.8 23 | pycparser==2.21 24 | pydantic==1.9.1 25 | pyparsing==3.0.9 26 | python-dotenv==0.20.0 27 | python-jose==3.3.0 28 | python-multipart==0.0.5 29 | PyYAML==6.0 30 | redis==4.3.1 31 | rsa==4.8 32 | six==1.16.0 33 | sniffio==1.2.0 34 | starlette==0.19.1 35 | typing_extensions==4.2.0 36 | uvicorn==0.17.6 37 | watchgod==0.8.2 38 | websockets==10.3 39 | wrapt==1.14.1 40 | -------------------------------------------------------------------------------- /local/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | asgiref==3.5.2 3 | async-timeout==4.0.2 4 | bcrypt==3.2.2 5 | cassandra-driver==3.25.0 6 | cffi==1.15.0 7 | click==8.1.3 8 | colorama==0.4.4 9 | cryptography==37.0.2 10 | Deprecated==1.2.13 11 | dnspython==2.2.1 12 | ecdsa==0.17.0 13 | email-validator==1.2.1 14 | fastapi==0.78.0 15 | geomet==0.2.1.post1 16 | gunicorn==20.1.0 17 | h11==0.13.0 18 | httptools==0.4.0 19 | idna==3.3 20 | packaging==21.3 21 | passlib==1.7.4 22 | pyasn1==0.4.8 23 | pycparser==2.21 24 | pydantic==1.9.1 25 | pyparsing==3.0.9 26 | python-dotenv==0.20.0 27 | python-jose==3.3.0 28 | python-multipart==0.0.5 29 | PyYAML==6.0 30 | redis==4.3.1 31 | rsa==4.8 32 | six==1.16.0 33 | sniffio==1.2.0 34 | starlette==0.19.1 35 | typing_extensions==4.2.0 36 | uvicorn==0.17.6 37 | watchgod==0.8.2 38 | websockets==10.3 39 | wrapt==1.14.1 40 | -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 小URL 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sudo apt update 4 | sudo apt install apt-transport-https ca-certificates curl software-properties-common 5 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - 6 | sudo add-apt-repository "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" 7 | sudo apt update 8 | apt-cache policy docker-ce 9 | sudo apt install docker-ce 10 | sudo systemctl status docker 11 | 12 | 13 | # Docker Compose 14 | compose_release() { 15 | curl --silent "https://api.github.com/repos/docker/compose/releases/latest" | 16 | grep -Po '"tag_name": "\K.*?(?=")' 17 | } 18 | 19 | if ! [ -x "$(command -v docker-compose)" ]; then 20 | sudo curl -L https://github.com/docker/compose/releases/download/$(compose_release)/docker-compose-$(uname -s)-$(uname -m) \ 21 | -o /usr/local/bin/docker-compose && sudo chmod +x /usr/local/bin/docker-compose 22 | fi 23 | 24 | 25 | chmod -R +x ./init-letsencrypt.sh && ./init-letsencrypt.sh -------------------------------------------------------------------------------- /backend/chi_url/errors.py: -------------------------------------------------------------------------------- 1 | from fastapi import HTTPException 2 | from starlette import status 3 | 4 | HTTP_USERNAME_ERROR = HTTPException( 5 | status_code=status.HTTP_403_FORBIDDEN, 6 | detail="Username already exists." 7 | ) 8 | 9 | 10 | HTTP_EMAIL_ERROR = HTTPException( 11 | status_code=status.HTTP_403_FORBIDDEN, 12 | detail="Email already exists." 13 | ) 14 | 15 | HTTP_401_UNAUTHORIZED = HTTPException( 16 | status_code=status.HTTP_401_UNAUTHORIZED, 17 | detail="Could not validate credentials", 18 | headers={"WWW-Authenticate": 'Bearer'} 19 | ) 20 | 21 | HTTP_401_EXPIRED_JWT = HTTPException( 22 | status_code=status.HTTP_401_UNAUTHORIZED, 23 | detail="Token Expired", 24 | ) 25 | 26 | HTTP_404_NOT_FOUND = HTTPException( 27 | status_code=status.HTTP_404_NOT_FOUND, 28 | detail="Page Not Found" 29 | ) 30 | 31 | HTTP_500_INTERNAL_SERVER_ERROR = HTTPException( 32 | status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, 33 | detail="Try again Later" 34 | ) -------------------------------------------------------------------------------- /frontend/src/Mycomponents/pages/userpages/userpage.css: -------------------------------------------------------------------------------- 1 | .visitedLink:link, .visitedLink:visited { 2 | color: #343434; 3 | cursor: pointer; 4 | } 5 | 6 | .visitedLink:link:active, .visitedLink:visited:active, .visitedLink:hover { 7 | color: white; 8 | text-decoration: none; 9 | background-color: #343434 10 | } 11 | 12 | .tableMargin { 13 | margin-bottom: 100px; 14 | } 15 | 16 | .fix-width { 17 | width: 100%; 18 | overflow-y: hidden; 19 | overflow-x: auto; 20 | -webkit-overflow-scrolling: touch; 21 | } 22 | 23 | .table1 { 24 | width: 700px; 25 | margin-bottom: 0; 26 | max-width: none; 27 | } 28 | 29 | 30 | 31 | .scroll-inner::-webkit-scrollbar { 32 | width: 10px; 33 | } 34 | 35 | .scroll-inner::-webkit-scrollbar:horizontal { 36 | height: 10px; 37 | } 38 | 39 | .scroll-inner::-webkit-scrollbar-track { 40 | background-color: transparentize(#ccc, 0.7); 41 | } 42 | 43 | .scroll-inner::-webkit-scrollbar-thumb { 44 | border-radius: 10px; 45 | background: transparentize(#ccc, 0.5); 46 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.5); 47 | } 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 CosmicOppai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /local/local_nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | server_name localhost; 4 | server_tokens off; 5 | 6 | root /usr/share/nginx/html; 7 | 8 | location = /home { 9 | index index.html index.htm; 10 | try_files $uri /index.html; 11 | } 12 | location = /user { 13 | index index.html index.htm; 14 | try_files $uri /index.html; 15 | } 16 | location = /login { 17 | index index.html index.htm; 18 | try_files $uri /index.html; 19 | } 20 | location = /signup { 21 | index index.html index.htm; 22 | try_files $uri /index.html; 23 | } 24 | 25 | location = /verify { 26 | index index.html index.htm; 27 | try_files $uri /index.html; 28 | } 29 | 30 | 31 | location ~ "^\/([0-9a-zA-Z+=\?\/\-_]{7,})$" { 32 | proxy_set_header Host $http_host; 33 | proxy_set_header X-Real-IP $remote_addr; 34 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 35 | proxy_pass 'http://backend:8000'; 36 | } 37 | } -------------------------------------------------------------------------------- /frontend/src/proxysetup.js: -------------------------------------------------------------------------------- 1 | const proxy = require("http-proxy-middleware") 2 | 3 | module.exports = function(App){ 4 | App.use( 5 | proxy("add_user",{ 6 | target: "http://backend:8000/", 7 | changeOrigin : true 8 | }) 9 | ); 10 | 11 | App.use( 12 | proxy("token",{ 13 | target:"http://backend:8000/", 14 | changeOrigin : true 15 | }) 16 | ); 17 | App.use( 18 | proxy("get_user/check/{username}",{ 19 | target:"http://backend:8000/", 20 | changeOrigin : true 21 | }) 22 | ); 23 | App.use( 24 | proxy("add_url",{ 25 | target:"http://backend:8000/", 26 | changeOrigin : true 27 | }) 28 | ); 29 | App.use( 30 | proxy("url-stats",{ 31 | target:"http://backend:8000/", 32 | changeOrigin : true 33 | }) 34 | ); 35 | App.use( 36 | proxy(`url-stats/?paging_state=${pagingStatus}`,{ 37 | target:"http://backend:8000/", 38 | changeOrigin : true 39 | }) 40 | ); 41 | App.use( 42 | proxy('send-code',{ 43 | target:"http://backend:8000/", 44 | changeOrigin : true 45 | }) 46 | ); 47 | }; -------------------------------------------------------------------------------- /cassandra/node1/cassandra/logback-tools.xml: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | System.err 23 | 24 | %-5level %date{"HH:mm:ss,SSS"} %msg%n 25 | 26 | 27 | WARN 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /backend/chi_url/delete_url.py: -------------------------------------------------------------------------------- 1 | from fastapi import status, APIRouter, Body, Depends, BackgroundTasks 2 | from session_token import get_current_active_user, User 3 | from db import session 4 | import errors 5 | from cache_backend import cache 6 | from pydantic import BaseModel, Field 7 | 8 | # Prepared Statement 9 | 10 | delete_url_stmt = session.prepare("DELETE FROM url_map WHERE short_url=?") 11 | delete_url_stat_stmt = session.prepare("DELETE FROM resolve_count WHERE user=? AND short_url=?") 12 | 13 | router = APIRouter() 14 | 15 | 16 | class Url(BaseModel): 17 | short_url: str = Field(title="Hashed URL", description="URL which has to be deleted", max_length=7, min_length=7) 18 | 19 | 20 | @router.post("/delete_url", status_code=status.HTTP_200_OK, tags=['url'], description="Route to delete the url", 21 | response_description="URL Successfully deleted") 22 | async def delete_url(background_tasks: BackgroundTasks, 23 | url: Url, 24 | _user: User = Depends(get_current_active_user)): 25 | short_url = url.short_url 26 | _user = _user.get("username", None) 27 | if not _user: 28 | return errors.HTTP_401_UNAUTHORIZED 29 | session.execute(delete_url_stmt, [short_url]) 30 | session.execute(delete_url_stat_stmt, [_user, short_url]) 31 | background_tasks.add_task(delete_url_from_cache, short_url) 32 | 33 | 34 | def delete_url_from_cache(short_url: str): 35 | cache.lpop(short_url) 36 | -------------------------------------------------------------------------------- /cassandra/node1/cassandra/jvm11-clients.options: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # jvm11-clients.options # 3 | # # 4 | # See jvm-clients.options. This file is specific for Java 11 and newer. # 5 | ########################################################################### 6 | 7 | ################### 8 | # JPMS SETTINGS # 9 | ################### 10 | 11 | -Djdk.attach.allowAttachSelf=true 12 | --add-exports java.base/jdk.internal.misc=ALL-UNNAMED 13 | --add-exports java.base/jdk.internal.ref=ALL-UNNAMED 14 | --add-exports java.base/sun.nio.ch=ALL-UNNAMED 15 | --add-exports java.management.rmi/com.sun.jmx.remote.internal.rmi=ALL-UNNAMED 16 | --add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED 17 | --add-exports java.rmi/sun.rmi.server=ALL-UNNAMED 18 | --add-exports java.sql/java.sql=ALL-UNNAMED 19 | 20 | --add-opens java.base/java.lang.module=ALL-UNNAMED 21 | --add-opens java.base/jdk.internal.loader=ALL-UNNAMED 22 | --add-opens java.base/jdk.internal.ref=ALL-UNNAMED 23 | --add-opens java.base/jdk.internal.reflect=ALL-UNNAMED 24 | --add-opens java.base/jdk.internal.math=ALL-UNNAMED 25 | --add-opens java.base/jdk.internal.module=ALL-UNNAMED 26 | --add-opens java.base/jdk.internal.util.jar=ALL-UNNAMED 27 | --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED 28 | 29 | # The newline in the end of file is intentional 30 | -------------------------------------------------------------------------------- /backend/chi_url/main.py: -------------------------------------------------------------------------------- 1 | from functools import lru_cache 2 | from fastapi import FastAPI 3 | from fastapi.middleware.cors import CORSMiddleware 4 | import add_url 5 | import delete_url 6 | import email_verification 7 | import session_token 8 | import url_routing 9 | import url_stats 10 | import users 11 | from config import OriginSettings 12 | 13 | app = FastAPI( 14 | title='小 URL', 15 | description='An URL Shortener written in python', 16 | version='0.1', 17 | contact={ 18 | "name": "CosmicOppai", 19 | "url": "https://github.com/Cosmicoppai/chi_url", 20 | "email": "comsicoppai@protonmail.com", 21 | }, 22 | license_info={ 23 | "name": "MIT", 24 | "url": "https://www.apache.org/licenses/LICENSE-2.0.html" 25 | }, 26 | docs_url=None, 27 | redoc_url=None 28 | ) 29 | 30 | 31 | @lru_cache() 32 | def get_origin(): 33 | return OriginSettings() 34 | 35 | 36 | _origins = get_origin() 37 | 38 | 39 | origin = [_origins.origin, _origins.origin2, _origins.origin3] 40 | 41 | app.add_middleware( 42 | CORSMiddleware, 43 | allow_origins=origin, 44 | allow_credentials=True, 45 | allow_headers=['*', ], 46 | allow_methods=['*', ] 47 | ) 48 | 49 | app.include_router(session_token.router) 50 | app.include_router(users.router) 51 | app.include_router(email_verification.router) 52 | app.include_router(add_url.router) 53 | app.include_router(url_stats.router) 54 | app.include_router(delete_url.router) 55 | app.include_router(url_routing.router) 56 | -------------------------------------------------------------------------------- /cassandra/node1/cassandra/cassandra-topology.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Cassandra Node IP=Data Center:Rack 18 | 192.168.1.100=DC1:RAC1 19 | 192.168.2.200=DC2:RAC2 20 | 21 | 10.0.0.10=DC1:RAC1 22 | 10.0.0.11=DC1:RAC1 23 | 10.0.0.12=DC1:RAC2 24 | 25 | 10.20.114.10=DC2:RAC1 26 | 10.20.114.11=DC2:RAC1 27 | 28 | 10.21.119.13=DC3:RAC1 29 | 10.21.119.10=DC3:RAC1 30 | 31 | 10.0.0.13=DC1:RAC2 32 | 10.21.119.14=DC3:RAC2 33 | 10.20.114.15=DC2:RAC2 34 | 35 | # default for unknown nodes 36 | default=DC1:r1 37 | 38 | # Native IPv6 is supported, however you must escape the colon in the IPv6 Address 39 | # Also be sure to comment out JVM_OPTS="$JVM_OPTS -Djava.net.preferIPv4Stack=true" 40 | # in cassandra-env.sh 41 | fe80\:0\:0\:0\:202\:b3ff\:fe1e\:8329=DC1:RAC3 -------------------------------------------------------------------------------- /backend/chi_url/db.py: -------------------------------------------------------------------------------- 1 | import time 2 | from cassandra import ConsistencyLevel 3 | from cassandra.cluster import Cluster, ExecutionProfile, EXEC_PROFILE_DEFAULT 4 | from cassandra.policies import DCAwareRoundRobinPolicy 5 | import logging 6 | from cassandra.auth import PlainTextAuthProvider 7 | from config import Settings 8 | from functools import lru_cache 9 | 10 | 11 | @lru_cache() 12 | def db_cred(): 13 | return Settings() 14 | 15 | 16 | _cred = db_cred() # Load the cred from the .env 17 | 18 | """ 19 | Load the database credentials and keyspace name from the Environment Variables 20 | """ 21 | _username = _cred.db_username 22 | _password = _cred.db_password 23 | _keyspace = _cred.keyspace 24 | 25 | 26 | # Database log 27 | logging.basicConfig(handlers=[logging.FileHandler(filename='../logs/debug.log', encoding='utf-8')], level=logging.DEBUG) 28 | logging.basicConfig(handlers=[logging.FileHandler(filename='../logs/db_error.log', encoding='utf-8')], level=logging.ERROR) 29 | 30 | profiles = ExecutionProfile( 31 | load_balancing_policy=DCAwareRoundRobinPolicy(), 32 | consistency_level=ConsistencyLevel.ONE, 33 | request_timeout=15, 34 | ) 35 | 36 | _AUTH_PROVIDER = PlainTextAuthProvider(username=_username, password=_password) 37 | 38 | _CLUSTER = Cluster(contact_points=['node-1',],port=9042, ssl_context=None, 39 | protocol_version=5, 40 | auth_provider=_AUTH_PROVIDER, 41 | execution_profiles={EXEC_PROFILE_DEFAULT: profiles}) 42 | 43 | while True: 44 | try: 45 | session = _CLUSTER.connect(_keyspace) 46 | break 47 | except: 48 | time.sleep(10) # wait before reconnecting 49 | -------------------------------------------------------------------------------- /backend/chi_url/url_routing.py: -------------------------------------------------------------------------------- 1 | from add_url import add_resolve_count 2 | from fastapi import APIRouter, Path, BackgroundTasks 3 | from starlette.responses import RedirectResponse 4 | from db import session 5 | import errors 6 | from cache_backend import cache 7 | import redis 8 | 9 | url_get_stmt = session.prepare("SELECT url,user From url_map WHERE short_url=?") 10 | 11 | router = APIRouter() 12 | 13 | 14 | @router.get("/{hashed_url}", tags=["url"]) 15 | async def get_url(background_tasks: BackgroundTasks, 16 | hashed_url: str = Path(..., title="hashed url", 17 | description="Hashed url which is stored in the DB as key")): 18 | try: 19 | _url = cache.lrange(hashed_url, 0, 1) # check the cache 20 | if _url: 21 | url, user = _url[0].decode("utf-8"), _url[1].decode("utf-8") 22 | else: 23 | url, user = get_url_from_db(hashed_url) 24 | background_tasks.add_task(add_cache, hashed_url, *[user, url]) # cache the result using tail push 25 | except redis.exceptions.ConnectionError: # If Redis backend is not available hit the Database 26 | url, user = get_url_from_db(hashed_url) 27 | 28 | background_tasks.add_task(add_resolve_count, url, hashed_url, user) # update the resolveCount in the background 29 | return RedirectResponse(url=f"{url}") # Redirect to the mapped url from the DB ♥ 30 | 31 | 32 | def add_cache(short_url: str, *values): 33 | cache.lpush(short_url, *values) 34 | 35 | 36 | def get_url_from_db(short_url: str): 37 | try: 38 | _url = session.execute(url_get_stmt, [short_url])[0] 39 | return _url[0], _url[1] 40 | except IndexError or TypeError: 41 | raise errors.HTTP_404_NOT_FOUND 42 | -------------------------------------------------------------------------------- /frontend/src/Mycomponents/pages/Homepages/home.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Main } from './main' 3 | import { Page } from './page' 4 | import Nav from '../components/nav' 5 | import Footer from "../components/footer" 6 | import { Link } from 'react-router-dom' 7 | import './home.css' 8 | 9 | 10 | 11 | const Home = () => { 12 | 13 | return ( 14 |
15 |
16 |
17 |
18 |
19 |
21 |
22 | 23 |
24 |

Welcome!

25 | 26 | 27 |
28 |

We are URL shortener service that provide you to create short links from very long URLs. Our short links are only seven characters long, which makes them easier to type, present, or tweet.

29 |
30 | Sign up 31 | Login 32 |
33 |
34 |
35 | 36 | 37 | 38 |
39 |
40 |
41 | ) 42 | } 43 | 44 | export default Home -------------------------------------------------------------------------------- /cassandra/node1/cassandra/metrics-reporter-config-sample.yaml: -------------------------------------------------------------------------------- 1 | # For details see: 2 | # * http://wiki.apache.org/cassandra/Metrics 3 | # * https://github.com/addthis/metrics-reporter-config 4 | 5 | # This is an example file for configuring which metrics should go 6 | # where. The sample sends everything to a flat file for humans to 7 | # poke at. metrics-ganglia or metrics-graphite are more likely to 8 | # operationally useful. 9 | 10 | # Some metrics are global for a node (KeyCache capacity) while others 11 | # are broken down by column family or even IP. The sample list 12 | # includes all of the global metrics via a while list. To include 13 | # metrics for the system column family for example add 14 | # "^org.apache.cassandra.metrics.ColumnFamily.system.+". 15 | 16 | 17 | # Start Cassandra with 18 | # -Dcassandra.metricsReporterConfigFile=metrics-reporter-config.yaml 19 | # for this file to be used. If you are using metrics-ganglia, 20 | # metrics-graphite, or a custom reporter you will also have to add those 21 | # jars to the lib directory. Nothing in this file can affect 22 | # jmx metrics. 23 | 24 | 25 | console: 26 | - 27 | outfile: '/tmp/metrics.out' 28 | period: 10 29 | timeunit: 'SECONDS' 30 | predicate: 31 | color: "white" 32 | useQualifiedName: true 33 | patterns: 34 | - "^org.apache.cassandra.metrics.Cache.+" 35 | - "^org.apache.cassandra.metrics.ClientRequest.+" # includes ClientRequestMetrics 36 | - "^org.apache.cassandra.metrics.CommitLog.+" 37 | - "^org.apache.cassandra.metrics.Compaction.+" 38 | - "^org.apache.cassandra.metrics.DroppedMessage.+" 39 | - "^org.apache.cassandra.metrics.ReadRepair.+" 40 | - "^org.apache.cassandra.metrics.Storage.+" 41 | - "^org.apache.cassandra.metrics.ThreadPools.+" 42 | -------------------------------------------------------------------------------- /nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name pbl.asia; 4 | server_tokens off; 5 | 6 | location /.well-known/acme-challenge/ { 7 | root /var/www/certbot; 8 | } 9 | location / { 10 | root /var/www/certbot; 11 | return https://pbl.asia$request_uri; 12 | } 13 | } 14 | 15 | server { 16 | listen 443 ssl http2 default_server; 17 | listen [::]:443 ssl http2; 18 | server_name pbl.asia www.pbl.asia; 19 | server_tokens off; 20 | 21 | 22 | root /usr/share/nginx/html; 23 | 24 | location = /home { 25 | index index.html index.htm; 26 | try_files $uri /index.html; 27 | } 28 | location = /user { 29 | index index.html index.htm; 30 | try_files $uri /index.html; 31 | } 32 | location = /login { 33 | index index.html index.htm; 34 | try_files $uri /index.html; 35 | } 36 | location = /signup { 37 | index index.html index.htm; 38 | try_files $uri /index.html; 39 | } 40 | 41 | location = /verify { 42 | index index.html index.htm; 43 | try_files $uri /index.html; 44 | } 45 | 46 | 47 | location ~ "^\/([0-9a-zA-Z+=\?\/\-_]{7,})$" { 48 | proxy_set_header Host $http_host; 49 | proxy_set_header X-Real-IP $remote_addr; 50 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 51 | proxy_pass 'http://backend:8000'; 52 | } 53 | 54 | ssl_certificate /etc/letsencrypt/live/pbl.asia/fullchain.pem; 55 | ssl_certificate_key /etc/letsencrypt/live/pbl.asia/privkey.pem; 56 | include /etc/letsencrypt/options-ssl-nginx.conf; 57 | ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 58 | 59 | } -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pbl.asia", 3 | "homepage": ".", 4 | "version": "0.1.0", 5 | "private": false, 6 | "dependencies": { 7 | "@babel/eslint-parser": "^7.15.4", 8 | "@hapi/hoek": "^9.2.0", 9 | "@rollup/plugin-babel": "^5.3.0", 10 | "@sideway/address": "^4.1.2", 11 | "@testing-library/jest-dom": "^5.14.1", 12 | "@testing-library/react": "^12.0.0", 13 | "@testing-library/user-event": "^13.2.1", 14 | "@ungap/url-search-params": "^0.2.2", 15 | "bootstrap": "^5.1.3", 16 | "axios": "^0.24.0", 17 | "chokidar": "^3.5.2", 18 | "eslint-plugin-react": "^7.25.1", 19 | "joi": "^17.4.2", 20 | "lodash": "^4.17.21", 21 | "react": "^17.0.2", 22 | "react-dom": "^17.0.2", 23 | "react-router-dom": "^6.0.1", 24 | "react-scripts": "^4.0.3", 25 | "resolve-url": "^0.2.1", 26 | "sane": "^5.0.1", 27 | "urix": "^0.1.0", 28 | "uuid": "^8.3.2", 29 | "web-vitals": "^2.1.0" 30 | }, 31 | "scripts": { 32 | "preinstall": "npx npm-force-resolutions", 33 | "start": "react-scripts start", 34 | "build": "react-scripts build", 35 | "test": "react-scripts test", 36 | "eject": "react-scripts eject" 37 | }, 38 | "resolutions": { 39 | "ansi-regex": "5.0.1", 40 | "nth-check": ">=2.0.1", 41 | "tmpl": ">=1.0.5", 42 | "immer": ">=9.0.6", 43 | "axios": ">=0.21.2", 44 | "follow-redirects": ">=1.14.7", 45 | "node-forge": ">=1.0.0" 46 | }, 47 | "eslintConfig": { 48 | "extends": [ 49 | "react-app", 50 | "react-app/jest" 51 | ] 52 | }, 53 | "browserslist": { 54 | "production": [ 55 | ">0.2%", 56 | "not dead", 57 | "not op_mini all" 58 | ], 59 | "development": [ 60 | "last 1 chrome version", 61 | "last 1 firefox version", 62 | "last 1 safari version" 63 | ] 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Readme.MD: -------------------------------------------------------------------------------- 1 | # 小 URL 2 | ![GitHub contributors](https://img.shields.io/github/contributors/cosmicoppai/chi_url?color=lightgrey) 3 | [![GitHub forks](https://img.shields.io/github/forks/cosmicoppai/chi_url?color=lightgrey)](https://github.com/Cosmicoppai/chi_url/network) 4 | [![GitHub stars](https://img.shields.io/github/stars/cosmicoppai/chi_url?color=lightgrey)](https://github.com/Cosmicoppai/chi_url/stargazers) 5 | [![GitHub issues](https://img.shields.io/github/issues/Cosmicoppai/chi_url?color=lightgrey)](https://github.com/Cosmicoppai/chi_url/issues) 6 | [![MIT License](https://img.shields.io/badge/license-MIT-lightgrey)](./LICENSE) 7 | 8 | ## About 9 | icon 10 | An URL Shortener developed using FASTAPI, Cassandra, React and deployed using containers on cloud. 11 | 12 | - Easy to Scale 13 | - Highly available 14 | - Provide stats 15 | - ... etc 16 | 17 | ## Simplified Architecture 18 | ![Architecture](static/architecture.png) 19 | 20 | ## Tech Stack 21 | > ### Backend 22 | > * FASTAPI 23 | > ### Front-End 24 | > * REACT 25 | > ### Database 26 | > * Cassandra 27 | > ### Load Balancer and Reverse Proxy 28 | > * Nginx 29 | > ### Cloud Platform 30 | > * Linode 31 | > ### Container Tool 32 | > * Docker 33 | > ### Caching Backend 34 | > * Redis 35 | 36 | 37 | ## SetUp and Installation 38 | 39 | Clone the repository 40 | ``` 41 | git clone https://github.com/Cosmicoppai/chi_url 42 | ``` 43 | Create a virtual environment 44 | ``` 45 | virtualenv venv -p python3 46 | ``` 47 | Install the dependencies 48 | ``` 49 | pip install -r local/requirements.txt 50 | ``` 51 | add the key-value pairs in local/.env 52 | 53 | ``` 54 | cd local 55 | 56 | docker-compose up 57 | ``` 58 | App should be running on [localhost](http://localhost) 59 | 60 | ## License 61 | [MIT](http://opensource.org/licenses/MIT) © [CosmicOppai](https://github.com/cosmicoppai) -------------------------------------------------------------------------------- /frontend/src/Mycomponents/pages/components/footer.js: -------------------------------------------------------------------------------- 1 | import { React, useState} from 'react'; 2 | const Footer = () => { 3 | const [user, setUser] = useState({}); 4 | setInterval(() => { 5 | const userstr = localStorage.getItem("token") 6 | setUser(userstr); 7 | }, 1) 8 | return ( 9 |
10 | {user && ( 11 |
12 |
13 | Copyright ©小URL 14 |
15 |
16 | 17 | 18 |
19 |
20 | 21 | )} 22 | {!user && ( 23 |
24 |
25 | Copyright ©小URL 26 |
27 |
28 | 29 | 30 |
31 |
32 | )} 33 |
34 | 35 | ) 36 | } 37 | 38 | export default Footer 39 | 40 | -------------------------------------------------------------------------------- /local/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | 4 | #Node 1 5 | node-1: 6 | image: cassandra:4.0.4 7 | container_name: node-1 8 | environment: &environment 9 | - CASSANDRA_CLUSTER_NAME=cluster1 10 | - CASSANDRA_DC=Mumbai 11 | - CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch 12 | - CASSANDRA_SEEDS=node-1 13 | volumes: 14 | - node1-vol:/var/lib/cassandra 15 | - ../cassandra/node1/cassandra:/etc/cassandra 16 | restart: always 17 | 18 | # schema loading node 19 | pseudo-node: 20 | image: cassandra:4.0.4 21 | container_name: pseudo-node 22 | environment: *environment 23 | volumes: 24 | - ../cassandra/init_keyspace.cql:/schema.cql 25 | depends_on: 26 | - node-1 27 | command: /bin/bash -c "sleep 60 && cqlsh node-1 -f /schema.cql -u cassandra -p cassandra" 28 | restart: on-failure 29 | 30 | # Backend 31 | backend: 32 | build: 33 | context: ../backend 34 | container_name: backend 35 | depends_on: 36 | - pseudo-node 37 | env_file: 38 | - .env 39 | ports: 40 | - "8000:8000" 41 | restart: always 42 | 43 | # Frontend 44 | frontend: 45 | build: 46 | context: ../frontend 47 | container_name: frontend 48 | depends_on: 49 | - backend 50 | volumes: 51 | - react_build:/frontend/build 52 | 53 | # Redis 54 | redis: 55 | image: redis 56 | depends_on: 57 | - backend 58 | restart: always 59 | 60 | # Nginx service 61 | nginx: 62 | image: nginx:1.21-alpine 63 | ports: 64 | - "80:80" 65 | volumes: 66 | - ./local_nginx:/etc/nginx/conf.d 67 | - react_build:/usr/share/nginx/html 68 | command: "/bin/sh -c 'nginx -g \"daemon off;\"'" 69 | depends_on: 70 | - backend 71 | - frontend 72 | restart: always 73 | 74 | # Volumes 75 | volumes: 76 | node1-vol: 77 | react_build: -------------------------------------------------------------------------------- /backend/chi_url/url_stats.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter, status, Depends 2 | from session_token import get_current_active_user 3 | import binascii, errors 4 | from db import session 5 | from functools import lru_cache 6 | from config import OriginSettings 7 | from pydantic import BaseModel 8 | import logging 9 | 10 | logging.basicConfig(handlers=[logging.FileHandler(filename="../logs/url_stats.log", encoding="utf-8")], 11 | level=logging.ERROR) 12 | 13 | router = APIRouter() 14 | 15 | url_stats_stmt = session.prepare("SELECT * FROM resolve_count WHERE user=?") # Get URL Stats 16 | url_stats_stmt.fetch_size = 25 # set the pagination 25 17 | 18 | 19 | @lru_cache() 20 | def get_host_name(): 21 | return OriginSettings() 22 | 23 | 24 | class Host(BaseModel): 25 | host: str = get_host_name().host 26 | 27 | 28 | @router.get("/url_stats", tags=["url"], status_code=status.HTTP_200_OK) 29 | async def url_stats(paging_state=None, _user=Depends(get_current_active_user)): 30 | _user = _user.get('username', None) 31 | if _user: 32 | # statement = SimpleStatement(f"SELECT * FROM resolve_count WHERE user='{_user}'", fetch_size=25) 33 | ps = binascii.unhexlify(paging_state) if paging_state else None # check if paging state exists or not 34 | results = session.execute(url_stats_stmt, [_user], paging_state=ps) 35 | data = [] 36 | for stat in results.current_rows: 37 | data.append( 38 | {"url": stat.url, 39 | "short_url": f"{Host().host}/{stat.short_url}", 40 | "resolves": stat.resolves} 41 | ) 42 | paging_state = binascii.hexlify( 43 | results.paging_state).decode() if results.paging_state else None # fi all results are queried set paging_state as None 44 | return {"stats": data, "paging_state": paging_state} # return the data and the paging state 45 | 46 | raise errors.HTTP_401_UNAUTHORIZED 47 | -------------------------------------------------------------------------------- /backend/chi_url/users.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter, Path, status, BackgroundTasks 2 | import logging 3 | from pydantic import BaseModel, EmailStr 4 | from db import session 5 | from session_token import get_password_hash 6 | import email_verification 7 | from errors import HTTP_EMAIL_ERROR, HTTP_USERNAME_ERROR 8 | 9 | # Error log 10 | logging.basicConfig(handlers=[logging.FileHandler(filename="../logs/main.log", encoding="utf-8")], level=logging.ERROR) 11 | user_add_stmt = session.prepare( 12 | "INSERT INTO user (user_name, disabled, email, hashed_password) VALUES (?, TRUE, ?, ?)") # prepared statement to add user 13 | 14 | router = APIRouter() 15 | 16 | 17 | class User(BaseModel): 18 | username: str 19 | email: EmailStr 20 | password: str 21 | 22 | 23 | @router.post("/add_user", tags=["users"], status_code=status.HTTP_201_CREATED) 24 | async def add_user(user: User, background_tasks: BackgroundTasks): 25 | exist = await check_user(user.username, user.email) 26 | if not exist: 27 | _password = get_password_hash(user.password) 28 | session.execute(user_add_stmt, 29 | [user.username, user.email, _password]) # replace the pre_stmt with the actual values 30 | background_tasks.add_task(email_verification.send_verification_code, user.username, user.email) 31 | return True 32 | 33 | 34 | @router.get("/get_user/check/{username}", tags=["users"]) 35 | async def check_user(username: str = Path(..., title="username", description="username of the user"), 36 | email: str = None): # Check if user exists or not. 37 | try: 38 | if email: 39 | if session.execute(f"SELECT user_name FROM user WHERE email='{email}'").one(): 40 | raise HTTP_EMAIL_ERROR 41 | if session.execute(f"SELECT user_name FROM user WHERE user_name='{username}'").one(): 42 | raise HTTP_USERNAME_ERROR 43 | else: 44 | return False 45 | except TypeError: 46 | return False 47 | -------------------------------------------------------------------------------- /frontend/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Login from "./Mycomponents/pages/signuppages/login"; 3 | import Signup from "./Mycomponents/pages/signuppages/signup" 4 | import Verifymail from "./Mycomponents/pages/signuppages/verifymail"; 5 | import Home from "./Mycomponents/pages/Homepages/home"; 6 | import UserPage from "./Mycomponents/pages/userpages/userpage"; 7 | import { BrowserRouter as Router, Navigate, Route, Routes } from "react-router-dom"; 8 | import ErrorPage from './Mycomponents/pages/Homepages/errorPage'; 9 | 10 | 11 | function App() { 12 | function NotActiveRoute({ children }) { 13 | const auth = localStorage.getItem("token"); 14 | const active = localStorage.getItem("active"); 15 | return auth && (active === 'false')? children : ; 16 | } 17 | function ActiveRoute({ children }) { 18 | const auth = localStorage.getItem("token"); 19 | const active = localStorage.getItem("active"); 20 | return auth && (active === 'true') ? children : ; 21 | } 22 | function HomeRoute({ children }) { 23 | const auth = localStorage.getItem("token"); 24 | return !auth ? children : 25 | } 26 | return ( 27 | <> 28 | 29 | 30 | 32 | 33 | } /> 34 | 36 | 37 | 38 | } /> 39 | 41 | 42 | 43 | } /> 44 | 46 | 47 | } /> 48 | 50 | 51 | } /> 52 | } /> 53 | 54 | 55 | 56 | 57 | 58 | ) 59 | } 60 | 61 | export default App 62 | -------------------------------------------------------------------------------- /cassandra/node1/cassandra/cassandra-rackdc.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # These properties are used with GossipingPropertyFileSnitch and will 18 | # indicate the rack and dc for this node 19 | dc= Mumbai 20 | rack=rack1 21 | 22 | # Add a suffix to a datacenter name. Used by the Ec2Snitch and Ec2MultiRegionSnitch 23 | # to append a string to the EC2 region name. 24 | #dc_suffix= 25 | 26 | # Uncomment the following line to make this snitch prefer the internal ip when possible, as the Ec2MultiRegionSnitch does. 27 | # prefer_local=true 28 | 29 | # Datacenter and rack naming convention used by the Ec2Snitch and Ec2MultiRegionSnitch. 30 | # Options are: 31 | # legacy : datacenter name is the part of the availability zone name preceding the last "-" 32 | # when the zone ends in -1 and includes the number if not -1. Rack is the portion of 33 | # the availability zone name following the last "-". 34 | # Examples: us-west-1a => dc: us-west, rack: 1a; us-west-2b => dc: us-west-2, rack: 2b; 35 | # YOU MUST USE THIS VALUE IF YOU ARE UPGRADING A PRE-4.0 CLUSTER 36 | # standard : Default value. datacenter name is the standard AWS region name, including the number. 37 | # rack name is the region plus the availability zone letter. 38 | # Examples: us-west-1a => dc: us-west-1, rack: us-west-1a; us-west-2b => dc: us-west-2, rack: us-west-2b; 39 | # ec2_naming_scheme=standard 40 | -------------------------------------------------------------------------------- /cassandra/node1/cassandra/commitlog_archiving.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | # commitlog archiving configuration. Leave blank to disable. 19 | 20 | # Command to execute to archive a commitlog segment 21 | # Parameters: %path => Fully qualified path of the segment to archive 22 | # %name => Name of the commit log. 23 | # Example: archive_command=/bin/ln %path /backup/%name 24 | # 25 | # Limitation: *_command= expects one command with arguments. STDOUT 26 | # and STDIN or multiple commands cannot be executed. You might want 27 | # to script multiple commands and add a pointer here. 28 | archive_command= 29 | 30 | # Command to execute to make an archived commitlog live again. 31 | # Parameters: %from is the full path to an archived commitlog segment (from restore_directories) 32 | # %to is the live commitlog directory 33 | # Example: restore_command=/bin/cp -f %from %to 34 | restore_command= 35 | 36 | # Directory to scan the recovery files in. 37 | restore_directories= 38 | 39 | # Restore mutations created up to and including this timestamp in GMT. 40 | # Format: yyyy:MM:dd HH:mm:ss (2012:04:31 20:43:12) 41 | # 42 | # Recovery will continue through the segment when the first client-supplied 43 | # timestamp greater than this time is encountered, but only mutations less than 44 | # or equal to this timestamp will be applied. 45 | restore_point_in_time= 46 | 47 | # precision of the timestamp used in the inserts (MILLISECONDS, MICROSECONDS, ...) 48 | precision=MICROSECONDS 49 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | 4 | #Node 1 5 | node-1: 6 | image: cassandra:4.0 7 | container_name: node-1 8 | environment: &environment 9 | - CASSANDRA_CLUSTER_NAME=cluster1 10 | - CASSANDRA_DC=Mumbai 11 | - CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch 12 | - CASSANDRA_SEEDS=node-1 13 | volumes: 14 | - node1-vol:/var/lib/cassandra 15 | - ./cassandra/node1/cassandra:/etc/cassandra 16 | restart: always 17 | 18 | # schema loading node 19 | pseudo-node: 20 | image: cassandra:4.0 21 | container_name: pseudo-node 22 | environment: *environment 23 | volumes: 24 | - ./cassandra/init_keyspace.cql:/schema.cql 25 | depends_on: 26 | - node-1 27 | command: /bin/bash -c "sleep 60 && cqlsh node-1 -f /schema.cql -u cassandra -p cassandra" 28 | restart: on-failure 29 | 30 | # Backend 31 | backend: 32 | build: 33 | context: backend 34 | container_name: backend 35 | depends_on: 36 | - pseudo-node 37 | env_file: 38 | - .env 39 | ports: 40 | - "8000:8000" 41 | restart: always 42 | 43 | # Frontend 44 | frontend: 45 | build: 46 | context: frontend 47 | container_name: frontend 48 | volumes: 49 | - react_build:/frontend/build 50 | 51 | # Redis 52 | redis: 53 | image: redis 54 | depends_on: 55 | - backend 56 | restart: always 57 | 58 | # Nginx service 59 | nginx: 60 | image: nginx:1.21-alpine 61 | ports: 62 | - "80:80" 63 | - "443:443" 64 | volumes: 65 | - ./nginx:/etc/nginx/conf.d 66 | - ./data/certbot/conf:/etc/letsencrypt 67 | - ./data/certbot/www:/var/www/certbot 68 | - react_build:/usr/share/nginx/html 69 | command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'" 70 | depends_on: 71 | - backend 72 | - frontend 73 | restart: always 74 | 75 | #CertBot 76 | certbot: 77 | image: certbot/certbot 78 | volumes: 79 | - ./data/certbot/conf:/etc/letsencrypt 80 | - ./data/certbot/www:/var/www/certbot 81 | entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" 82 | depends_on: 83 | - nginx 84 | 85 | # Volumes 86 | volumes: 87 | node1-vol: 88 | react_build: -------------------------------------------------------------------------------- /frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | ### Node template 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | lerna-debug.log* 9 | node_modules 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | 46 | # Snowpack dependency directory (https://snowpack.dev/) 47 | web_modules/ 48 | 49 | # TypeScript cache 50 | *.tsbuildinfo 51 | 52 | # Optional npm cache directory 53 | .npm 54 | 55 | # Optional eslint cache 56 | .eslintcache 57 | 58 | # Microbundle cache 59 | .rpt2_cache/ 60 | .rts2_cache_cjs/ 61 | .rts2_cache_es/ 62 | .rts2_cache_umd/ 63 | 64 | # Optional REPL history 65 | .node_repl_history 66 | 67 | # Output of 'npm pack' 68 | *.tgz 69 | 70 | # Yarn Integrity file 71 | .yarn-integrity 72 | 73 | # dotenv environment variables file 74 | .env 75 | .env.test 76 | 77 | # parcel-bundler cache (https://parceljs.org/) 78 | .cache 79 | .parcel-cache 80 | 81 | # Next.js build output 82 | .next 83 | out 84 | 85 | # Nuxt.js build / generate output 86 | .nuxt 87 | dist 88 | 89 | # Gatsby files 90 | .cache/ 91 | # Comment in the public line in if your project uses Gatsby and not Next.js 92 | # https://nextjs.org/blog/next-9-1#public-directory-support 93 | # public 94 | 95 | # vuepress build output 96 | .vuepress/dist 97 | 98 | # Serverless directories 99 | .serverless/ 100 | 101 | # FuseBox cache 102 | .fusebox/ 103 | 104 | # DynamoDB Local files 105 | .dynamodb/ 106 | 107 | # TernJS port file 108 | .tern-port 109 | 110 | # Stores VSCode versions used for testing VSCode extensions 111 | .vscode-test 112 | 113 | # yarn v2 114 | .yarn/cache 115 | .yarn/unplugged 116 | .yarn/build-state.yml 117 | .yarn/install-state.gz 118 | .pnp.* 119 | 120 | Dockerfile 121 | .gitignore 122 | .dockerignore -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '37 2 * * 6' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript', 'python' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v2 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v1 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v1 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v1 71 | -------------------------------------------------------------------------------- /init-letsencrypt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if ! [ -x "$(command -v docker-compose)" ]; then 4 | echo 'Error: docker-compose is not installed.' >&2 5 | exit 1 6 | fi 7 | 8 | domains=(pbl.asia www.pbl.asia) 9 | rsa_key_size=4096 10 | data_path="./data/certbot" 11 | email="" # Adding a valid address is strongly recommended 12 | staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits 13 | 14 | if [ -d "$data_path" ]; then 15 | read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision 16 | if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then 17 | exit 18 | fi 19 | fi 20 | 21 | 22 | if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then 23 | echo "### Downloading recommended TLS parameters ..." 24 | mkdir -p "$data_path/conf" 25 | curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf" 26 | curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem" 27 | echo 28 | fi 29 | 30 | echo "### Creating dummy certificate for $domains ..." 31 | path="/etc/letsencrypt/live/$domains" 32 | mkdir -p "$data_path/conf/live/$domains" 33 | sudo docker-compose run --rm --entrypoint "\ 34 | openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 1\ 35 | -keyout '$path/privkey.pem' \ 36 | -out '$path/fullchain.pem' \ 37 | -subj '/CN=localhost'" certbot 38 | echo 39 | 40 | 41 | echo "### Starting nginx ..." 42 | sudo docker-compose up --force-recreate -d nginx 43 | echo 44 | 45 | echo "### Deleting dummy certificate for $domains ..." 46 | sudo docker-compose run --rm --entrypoint "\ 47 | rm -Rf /etc/letsencrypt/live/$domains && \ 48 | rm -Rf /etc/letsencrypt/archive/$domains && \ 49 | rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot 50 | echo 51 | 52 | 53 | echo "### Requesting Let's Encrypt certificate for $domains ..." 54 | #Join $domains to -d args 55 | domain_args="" 56 | for domain in "${domains[@]}"; do 57 | domain_args="$domain_args -d $domain" 58 | done 59 | 60 | # Select appropriate email arg 61 | case "$email" in 62 | "") email_arg="--register-unsafely-without-email" ;; 63 | *) email_arg="--email $email" ;; 64 | esac 65 | 66 | # Enable staging mode if needed. 67 | if [ $staging != "0" ]; then staging_arg="--staging"; fi 68 | 69 | sudo docker-compose run --rm --entrypoint "\ 70 | certbot certonly --webroot -w /var/www/certbot \ 71 | $staging_arg \ 72 | $email_arg \ 73 | $domain_args \ 74 | --rsa-key-size $rsa_key_size \ 75 | --agree-tos \ 76 | --force-renewal" certbot 77 | echo 78 | 79 | echo "### Reloading nginx ..." 80 | sudo docker-compose exec nginx nginx -s reload -------------------------------------------------------------------------------- /cassandra/node1/cassandra/jvm8-server.options: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # jvm8-server.options # 3 | # # 4 | # See jvm-server.options. This file is specific for Java 8 and newer. # 5 | ########################################################################### 6 | 7 | ######################## 8 | # GENERAL JVM SETTINGS # 9 | ######################## 10 | 11 | # allows lowering thread priority without being root on linux - probably 12 | # not necessary on Windows but doesn't harm anything. 13 | # see http://tech.stolsvik.com/2010/01/linux-java-thread-priorities-workaround.html 14 | -XX:ThreadPriorityPolicy=42 15 | 16 | ################# 17 | # GC SETTINGS # 18 | ################# 19 | 20 | ### CMS Settings 21 | -XX:+UseParNewGC 22 | -XX:+UseConcMarkSweepGC 23 | -XX:+CMSParallelRemarkEnabled 24 | -XX:SurvivorRatio=8 25 | -XX:MaxTenuringThreshold=1 26 | -XX:CMSInitiatingOccupancyFraction=75 27 | -XX:+UseCMSInitiatingOccupancyOnly 28 | -XX:CMSWaitDuration=10000 29 | -XX:+CMSParallelInitialMarkEnabled 30 | -XX:+CMSEdenChunksRecordAlways 31 | ## some JVMs will fill up their heap when accessed via JMX, see CASSANDRA-6541 32 | -XX:+CMSClassUnloadingEnabled 33 | 34 | ### G1 Settings 35 | ## Use the Hotspot garbage-first collector. 36 | #-XX:+UseG1GC 37 | #-XX:+ParallelRefProcEnabled 38 | 39 | # 40 | ## Have the JVM do less remembered set work during STW, instead 41 | ## preferring concurrent GC. Reduces p99.9 latency. 42 | #-XX:G1RSetUpdatingPauseTimePercent=5 43 | # 44 | ## Main G1GC tunable: lowering the pause target will lower throughput and vise versa. 45 | ## 200ms is the JVM default and lowest viable setting 46 | ## 1000ms increases throughput. Keep it smaller than the timeouts in cassandra.yaml. 47 | #-XX:MaxGCPauseMillis=500 48 | 49 | ## Optional G1 Settings 50 | # Save CPU time on large (>= 16GB) heaps by delaying region scanning 51 | # until the heap is 70% full. The default in Hotspot 8u40 is 40%. 52 | #-XX:InitiatingHeapOccupancyPercent=70 53 | 54 | # For systems with > 8 cores, the default ParallelGCThreads is 5/8 the number of logical cores. 55 | # Otherwise equal to the number of cores when 8 or less. 56 | # Machines with > 10 cores should try setting these to <= full cores. 57 | #-XX:ParallelGCThreads=16 58 | # By default, ConcGCThreads is 1/4 of ParallelGCThreads. 59 | # Setting both to the same value can reduce STW durations. 60 | #-XX:ConcGCThreads=16 61 | 62 | ### GC logging options -- uncomment to enable 63 | 64 | -XX:+PrintGCDetails 65 | -XX:+PrintGCDateStamps 66 | -XX:+PrintHeapAtGC 67 | -XX:+PrintTenuringDistribution 68 | -XX:+PrintGCApplicationStoppedTime 69 | -XX:+PrintPromotionFailure 70 | #-XX:PrintFLSStatistics=1 71 | #-Xloggc:/var/log/cassandra/gc.log 72 | -XX:+UseGCLogFileRotation 73 | -XX:NumberOfGCLogFiles=10 74 | -XX:GCLogFileSize=10M 75 | 76 | # The newline in the end of file is intentional 77 | -------------------------------------------------------------------------------- /backend/chi_url/add_url.py: -------------------------------------------------------------------------------- 1 | from fastapi import status, APIRouter, Depends, BackgroundTasks 2 | from session_token import get_current_active_user, User 3 | import time 4 | from pydantic import BaseModel 5 | from db import session 6 | import errors 7 | import logging 8 | 9 | logging.basicConfig(handlers=[logging.FileHandler(filename="../logs/add_url.log", encoding="utf-8")], level=logging.ERROR) 10 | 11 | router = APIRouter() 12 | 13 | url_add_stmt = session.prepare("Insert INTO url_map (short_url, created_on, url, user) VALUES (?, toTimestamp(now()), ?, ?)") 14 | check_short_url_stmt = session.prepare("SELECT url FROM url_map WHERE short_url=?") # whether the url already exists or not 15 | 16 | BASE_ALPH = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+=" 17 | BASE_LEN = 64 18 | 19 | 20 | class Url(BaseModel): 21 | url: str 22 | 23 | 24 | def encoding(_id): 25 | if not _id: 26 | return BASE_ALPH[0] 27 | _short_url = '' 28 | while _id: 29 | _id, rem = divmod(_id, BASE_LEN) 30 | _short_url = BASE_ALPH[rem] + _short_url 31 | return _short_url 32 | 33 | 34 | @router.post("/add_url", 35 | description="It'll accept a long url and save the hashed url in the database", tags=["url"], 36 | status_code=status.HTTP_201_CREATED, response_description="Short Url successfully created") 37 | async def add_url(background_tasks: BackgroundTasks, raw_url: Url, _user: User = Depends(get_current_active_user)): 38 | _user = _user.get('username', None) 39 | 40 | if _user: 41 | _time = str(time.time_ns())[::-1] # get the current time 42 | hex_num = int((_user + _time).encode().hex(), 16) # unique string consist of username+current_time 43 | 44 | """ 45 | Check if the short url already exist in DB or not. 46 | If exist check for the next value until its unique. 47 | return server Error if all possible values are checked 48 | """ 49 | for tri in range(10): 50 | hashed_url = encoding(hex_num)[tri:7 + tri] 51 | if session.execute(check_short_url_stmt, [hashed_url]).one(): # check if url already exists o not 52 | continue 53 | else: 54 | try: 55 | # raw_url is pydantic model, separate the url part 56 | session.execute(url_add_stmt, [hashed_url, raw_url.url, _user]) 57 | background_tasks.add_task(add_resolve_count, raw_url.url, hashed_url, _user) 58 | return {"short_url": hashed_url} 59 | 60 | except Exception as e: 61 | with open("../logs/db_error.log", 'a') as f: 62 | f.write(str(e)) 63 | 64 | raise errors.HTTP_500_INTERNAL_SERVER_ERROR 65 | 66 | raise errors.HTTP_401_UNAUTHORIZED 67 | 68 | 69 | def add_resolve_count(url: str, short_url: str, user: str): 70 | session.execute(f"UPDATE resolve_count SET resolves=resolves+1 WHERE user='{user}' AND url='{url}' AND short_url='{short_url}'") 71 | -------------------------------------------------------------------------------- /cassandra/init_keyspace.cql: -------------------------------------------------------------------------------- 1 | 2 | CREATE KEYSPACE IF NOT EXISTS chi_url WITH replication = {'class': 'NetworkTopologyStrategy', 'Mumbai': '1'} AND durable_writes = true; 3 | 4 | CREATE TABLE IF NOT EXISTS chi_url.resolve_count ( 5 | user text, 6 | url text, 7 | short_url text, 8 | resolves counter, 9 | PRIMARY KEY (user, short_url, url) 10 | ) WITH CLUSTERING ORDER BY (short_url ASC, url ASC) 11 | AND bloom_filter_fp_chance = 0.01 12 | AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'} 13 | AND cdc = false 14 | AND comment = '' 15 | AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'} 16 | AND compression = {'chunk_length_in_kb': '16', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'} 17 | AND crc_check_chance = 1.0 18 | AND default_time_to_live = 0 19 | AND gc_grace_seconds = 864000 20 | AND max_index_interval = 2048 21 | AND memtable_flush_period_in_ms = 0 22 | AND min_index_interval = 128 23 | AND speculative_retry = '99p'; 24 | 25 | CREATE TABLE IF NOT EXISTS chi_url.url_map ( 26 | short_url text, 27 | created_on timestamp, 28 | url text, 29 | user text, 30 | PRIMARY KEY (short_url, created_on) 31 | ) WITH CLUSTERING ORDER BY (created_on DESC) 32 | AND bloom_filter_fp_chance = 0.01 33 | AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'} 34 | AND cdc = false 35 | AND comment = '' 36 | AND compaction = {'class': 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy', 'sstable_size_in_mb': '160'} 37 | AND compression = {'chunk_length_in_kb': '16', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'} 38 | AND crc_check_chance = 1.0 39 | AND default_time_to_live = 0 40 | AND gc_grace_seconds = 864000 41 | AND max_index_interval = 2048 42 | AND memtable_flush_period_in_ms = 0 43 | AND min_index_interval = 128 44 | AND speculative_retry = '99p'; 45 | 46 | CREATE TABLE IF NOT EXISTS chi_url.user ( 47 | user_name text PRIMARY KEY, 48 | disabled boolean, 49 | email text, 50 | hashed_password text, 51 | verification_code text 52 | ) WITH bloom_filter_fp_chance = 0.01 53 | AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'} 54 | AND cdc = false 55 | AND comment = '' 56 | AND compaction = {'class': 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy', 'sstable_size_in_mb': '160'} 57 | AND compression = {'chunk_length_in_kb': '16', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'} 58 | AND crc_check_chance = 1.0 59 | AND default_time_to_live = 0 60 | AND gc_grace_seconds = 864000 61 | AND max_index_interval = 2048 62 | AND memtable_flush_period_in_ms = 0 63 | AND min_index_interval = 128 64 | AND speculative_retry = '99p'; 65 | 66 | CREATE INDEX IF NOT EXISTS email ON chi_url.user (email); 67 | 68 | CREATE ROLE IF NOT EXISTS cosmicoppai with superuser = true AND LOGIN = true and PASSWORD = 'dry-flower@04'; 69 | 70 | ALTER KEYSPACE "system_auth" WITH REPLICATION = {'class' : 'NetworkTopologyStrategy', 'Mumbai': 1}; -------------------------------------------------------------------------------- /frontend/src/Mycomponents/pages/signuppages/verifymail.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import React,{useState} from 'react' 3 | import { Link } from 'react-router-dom'; 4 | 5 | const Verifymail = () => { 6 | const [loading, setloading] = useState(false) 7 | const [sendBox, setsendBox] = useState(true) 8 | const [alertBox, setalertBox] = useState(false) 9 | 10 | const emailVerification = async () => { 11 | setsendBox(false) 12 | setloading(true) 13 | const token = localStorage.getItem("token"); 14 | await axios.get('send_code', { 15 | headers: { 16 | 'Authorization': ` Bearer ${token}`, 17 | 'Accept': 'application/json' 18 | } 19 | }) 20 | .then(resp => { 21 | localStorage.clear(); 22 | setloading(false) 23 | setalertBox(true) 24 | }) 25 | .catch(error => { 26 | // console.error(error); 27 | }) 28 | } 29 | 30 | let mystyle = { 31 | marginTop: "150px", 32 | marginBottom: "350px", 33 | } 34 | let mystyle2 = { 35 | marginTop: "205px", 36 | marginBottom: "350px", 37 | display: 'none' 38 | } 39 | 40 | 41 | return ( 42 | <> 43 | 56 | {sendBox &&( 57 |
58 |

Please Verify your email

59 |

Please click on the send button to recieve the 60 | verification link on your registered email id.

61 | 63 |
64 | )} 65 | {alertBox &&( 66 | 70 | )} 71 | {loading &&( 72 |
73 | Loading... 74 |
75 | )} 76 | 77 | 78 | ) 79 | } 80 | 81 | export default Verifymail 82 | -------------------------------------------------------------------------------- /cassandra/node1/cassandra/hotspot_compiler: -------------------------------------------------------------------------------- 1 | dontinline org.apache.cassandra.db.Columns$Serializer::deserializeLargeSubset (Lorg.apache.cassandra.io.util.DataInputPlus;Lorg.apache.cassandra.db.Columns;I)Lorg.apache.cassandra.db.Columns; 2 | dontinline org.apache.cassandra.db.Columns$Serializer::serializeLargeSubset (Ljava.util.Collection;ILorg.apache.cassandra.db.Columns;ILorg.apache.cassandra.io.util.DataOutputPlus;)V 3 | dontinline org.apache.cassandra.db.Columns$Serializer::serializeLargeSubsetSize (Ljava.util.Collection;ILorg.apache.cassandra.db.Columns;I)I 4 | dontinline org.apache.cassandra.db.commitlog.AbstractCommitLogSegmentManager::advanceAllocatingFrom (Lorg.apache.cassandra.db.commitlog.CommitLogSegment;)V 5 | dontinline org.apache.cassandra.db.transform.BaseIterator::tryGetMoreContents ()Z 6 | dontinline org.apache.cassandra.db.transform.StoppingTransformation::stop ()V 7 | dontinline org.apache.cassandra.db.transform.StoppingTransformation::stopInPartition ()V 8 | dontinline org.apache.cassandra.io.util.BufferedDataOutputStreamPlus::doFlush (I)V 9 | dontinline org.apache.cassandra.io.util.BufferedDataOutputStreamPlus::writeSlow (JI)V 10 | dontinline org.apache.cassandra.io.util.RebufferingInputStream::readPrimitiveSlowly (I)J 11 | exclude org.apache.cassandra.utils.JVMStabilityInspector::forceHeapSpaceOomMaybe (Ljava.lang.OutOfMemoryError;)V 12 | inline org.apache.cassandra.db.rows.UnfilteredSerializer::serializeRowBody (Lorg.apache.cassandra.db.rows.Row;ILorg.apache.cassandra.db.rows.SerializationHelper;Lorg.apache.cassandra.io.util.DataOutputPlus;)V 13 | inline org.apache.cassandra.io.util.Memory::checkBounds (JJ)V 14 | inline org.apache.cassandra.io.util.SafeMemory::checkBounds (JJ)V 15 | inline org.apache.cassandra.net.FrameDecoderWith8bHeader::decode (Ljava.util.Collection;Lorg.apache.cassandra.net.ShareableBytes;I)V 16 | inline org.apache.cassandra.service.reads.repair.RowIteratorMergeListener::applyToPartition (ILjava.util.function.Consumer;)V 17 | inline org.apache.cassandra.utils.AsymmetricOrdering::selectBoundary (Lorg.apache.cassandra.utils.AsymmetricOrdering.Op;II)I 18 | inline org.apache.cassandra.utils.AsymmetricOrdering::strictnessOfLessThan (Lorg.apache.cassandra.utils.AsymmetricOrdering.Op;)I 19 | inline org.apache.cassandra.utils.BloomFilter::indexes (Lorg.apache.cassandra.utils.IFilter.FilterKey;)[J 20 | inline org.apache.cassandra.utils.BloomFilter::setIndexes (JJIJ[J)V 21 | inline org.apache.cassandra.utils.ByteBufferUtil::compare (Ljava.nio.ByteBuffer;[B)I 22 | inline org.apache.cassandra.utils.ByteBufferUtil::compare ([BLjava.nio.ByteBuffer;)I 23 | inline org.apache.cassandra.utils.ByteBufferUtil::compareUnsigned (Ljava.nio.ByteBuffer;Ljava.nio.ByteBuffer;)I 24 | inline org.apache.cassandra.utils.FastByteOperations$UnsafeOperations::compareTo (Ljava.lang.Object;JILjava.lang.Object;JI)I 25 | inline org.apache.cassandra.utils.FastByteOperations$UnsafeOperations::compareTo (Ljava.lang.Object;JILjava.nio.ByteBuffer;)I 26 | inline org.apache.cassandra.utils.FastByteOperations$UnsafeOperations::compareTo (Ljava.nio.ByteBuffer;Ljava.nio.ByteBuffer;)I 27 | inline org.apache.cassandra.utils.memory.BufferPool$LocalPool::tryGetInternal (IZ)Ljava.nio.ByteBuffer; 28 | inline org.apache.cassandra.utils.vint.VIntCoding::encodeUnsignedVInt (JI)[B 29 | inline org.apache.cassandra.utils.vint.VIntCoding::encodeUnsignedVInt (JI[B)V 30 | inline org.apache.cassandra.utils.vint.VIntCoding::writeUnsignedVInt (JLjava.io.DataOutput;)V 31 | inline org.apache.cassandra.utils.vint.VIntCoding::writeUnsignedVInt (JLjava.nio.ByteBuffer;)V 32 | inline org.apache.cassandra.utils.vint.VIntCoding::writeVInt (JLjava.io.DataOutput;)V 33 | -------------------------------------------------------------------------------- /frontend/src/Mycomponents/pages/components/nav.js: -------------------------------------------------------------------------------- 1 | import { React, useState, useEffect } from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | const Nav = () => { 5 | const [user, setUser] = useState({}); 6 | useEffect(() => { 7 | setInterval(() => { 8 | const user = localStorage.getItem("token"); 9 | setUser(user); 10 | }, 1) 11 | }); 12 | const logout = () => { 13 | localStorage.clear(); 14 | window.location.replace("/login") 15 | } 16 | return ( 17 |
18 | 19 | 20 | {!user && ( 21 | <> 22 | 37 | 38 | )} 39 | {user && ( 40 | <> 41 | 62 | 63 | )} 64 |
65 | 66 | 67 | ) 68 | } 69 | 70 | export default Nav 71 | -------------------------------------------------------------------------------- /frontend/src/Mycomponents/pages/Homepages/page.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const Page = () => { 4 | 5 | return ( 6 | <> 7 | 8 |
9 |
10 |
11 |
12 | 13 |
14 |
15 |

Url Shortener

16 |

Free URL Shortener with many features that gives you better quality. Shortened URLs will never expire.

17 |
18 |
19 |
20 |
21 | 22 | 23 |
24 |
25 |

Easy to use

26 |

Once you Signup with us it is easy and fast, enter the long link to get your shortened link.

27 |
28 |
29 |
30 |
31 | 32 |
33 |
34 |

Link Statistics

35 |

We provide services where you can check the amount of clicks that your shortened url received

36 |
37 |
38 |
39 |
40 | 41 |
42 |
43 |

Compatible

44 |

Compatible with all devices such as desktop, tablets and phones

45 |
46 |
47 |
48 |
49 | 50 |
51 |
52 |

Reliable

53 |

All links that try to disseminate spam, viruses and malware are deleted

54 |
55 |
56 |
57 |
58 | 59 |
60 |
61 |

Security

62 |

Our services are fast and secure, our service have HTTPS protocol and data encryption

63 |
64 |
65 |
66 |
67 | 68 | 69 | ) 70 | } 71 | 72 | -------------------------------------------------------------------------------- /backend/chi_url/email_verification.py: -------------------------------------------------------------------------------- 1 | import ssl, random, smtplib 2 | from db import session 3 | from fastapi import status, APIRouter, Depends 4 | from datetime import timedelta, datetime 5 | from pydantic import EmailStr 6 | from session_token import SECRET_KEY, ALGORITHM 7 | from jose import jwt 8 | from email.header import Header 9 | from email.utils import formataddr 10 | from email.mime.text import MIMEText 11 | from email.mime.multipart import MIMEMultipart 12 | from config import EmailSettings, OriginSettings 13 | from functools import lru_cache 14 | from session_token import User, get_current_user 15 | from errors import HTTP_401_EXPIRED_JWT, HTTP_404_NOT_FOUND 16 | from starlette.responses import RedirectResponse 17 | from string import Template 18 | from email_template import EMAIL_TEMPLATE 19 | 20 | router = APIRouter() 21 | 22 | 23 | @lru_cache() 24 | def email_cred(): 25 | return EmailSettings() 26 | 27 | 28 | @lru_cache() 29 | def get_host_name(): 30 | return OriginSettings() 31 | 32 | 33 | _cred = email_cred() 34 | _host = get_host_name() 35 | 36 | _email_address = _cred.email 37 | _password = _cred.email_password 38 | 39 | 40 | def create_email_verification_token(data: dict): 41 | to_encode = data.copy() 42 | expire = datetime.utcnow() + timedelta(minutes=15) 43 | to_encode.update({'exp': expire}) 44 | encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) 45 | return encoded_jwt 46 | 47 | 48 | def send_verification_code(user: str, user_email: EmailStr): 49 | verification_code = random.randrange(100000, 1000000) 50 | verification_token = create_email_verification_token(data={'user': user, "verification_code": verification_code}) 51 | send_email(token=verification_token, user=user, user_email=user_email) # send the mail 52 | session.execute( 53 | f"UPDATE user SET verification_code='{verification_code}' WHERE user_name='{user}';") # update the verification code in the database 54 | 55 | return {"status": status.HTTP_200_OK, "message": "Email Sent"} 56 | 57 | 58 | def send_email(token: str, user: str, user_email: EmailStr): 59 | context = ssl.create_default_context() 60 | message = MIMEMultipart('alternative') 61 | with smtplib.SMTP_SSL('smtp.gmail.com', 465, context=context) as server: 62 | server.login(_email_address, _password) 63 | 64 | message['Subject'] = 'Verify Email' 65 | message['From'] = formataddr((str(Header('小 URL', 'utf-8')), _email_address)) 66 | message['To'] = user_email 67 | html = Template(EMAIL_TEMPLATE).substitute(name=user, url=f"{_host.host}/verify_email/?token={token}") 68 | message.attach(MIMEText(html, 'html')) 69 | server.send_message(message) 70 | 71 | 72 | @router.get('/verify_email/', tags=["users"]) 73 | async def verify_acc(token): 74 | """ 75 | Payload Format 76 | {'user': 'user', 'verification_code': 3000, 'exp': 1587960} :- Demo Data 77 | """ 78 | try: 79 | payload = jwt.decode(token, SECRET_KEY, ALGORITHM) 80 | except jwt.ExpiredSignatureError or jwt.JWTClaimsError: # check if token expired or not 81 | raise HTTP_401_EXPIRED_JWT 82 | _user: str = payload.get('user') # get the username from the token 83 | verification_code_from_jwt: str = payload.get('verification_code') # get the verification code 84 | _verification_code = session.execute(f"SELECT verification_code FROM user WHERE user_name='{_user}'").one()[ 85 | 0] # get the verification code from the database 86 | 87 | if verification_code_from_jwt == int(_verification_code): # check if both tokens are same or not 88 | session.execute( 89 | f"UPDATE user SET disabled=FALSE, verification_code=NULL WHERE user_name='{_user}'") # Activate the user 90 | return {"status": status.HTTP_200_OK, "message": "Email Successfully verified"} 91 | 92 | return {"status": status.HTTP_400_BAD_REQUEST, "message": "Verification code not valid"} 93 | 94 | 95 | @router.get("/send_code", status_code=status.HTTP_200_OK) # To send verification code again 96 | def resend_verification_code(_user: User = Depends(get_current_user)): # get the username from the jwt 97 | if _user.disable: 98 | _email = session.execute(f"SELECT email From user WHERE user_name='{_user.username}'").one()[ 99 | 0] # get the email id from the db 100 | send_verification_code(user=_user.username, user_email=_email) # call the function to send email 101 | return RedirectResponse(url=f"{_host.host}/user") 102 | return HTTP_404_NOT_FOUND 103 | -------------------------------------------------------------------------------- /backend/chi_url/session_token.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends, HTTPException, status, APIRouter 2 | from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm 3 | from pydantic import BaseModel 4 | from typing import Optional 5 | from passlib.context import CryptContext 6 | from datetime import datetime, timedelta 7 | from jose import jwt, JWTError 8 | from config import JWT_Settings 9 | from functools import lru_cache 10 | from db import session # Cassandra Database session 11 | from errors import HTTP_401_UNAUTHORIZED 12 | 13 | 14 | @lru_cache() 15 | def cached_keys(): 16 | return JWT_Settings() 17 | 18 | 19 | _keys = cached_keys() # Load the keys from the .env 20 | 21 | SECRET_KEY = _keys.secret_key # Load the secret key from env var 22 | ALGORITHM = _keys.algorithm # Load the white list of hashing algorithms 23 | ACCESS_TOKEN_EXPIRE_MINUTES = 10080 24 | 25 | 26 | router = APIRouter() 27 | 28 | 29 | class Token(BaseModel): 30 | access_token: str 31 | token_type: str 32 | 33 | 34 | class User(BaseModel): 35 | username: str 36 | disable: Optional[bool] = False 37 | 38 | 39 | class UserInDB(User): 40 | hashed_password: str 41 | 42 | 43 | oauth2_scheme = OAuth2PasswordBearer(tokenUrl="get_token") 44 | pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") 45 | 46 | 47 | # This func will hash the password using defined or set Algorithm 48 | def get_password_hash(password): 49 | return pwd_context.hash(password) 50 | 51 | 52 | # This func will compare the user typed password with the password stored in the database. 53 | def verify_password(plain_password, hashed_password): 54 | return pwd_context.verify(plain_password, hashed_password) 55 | 56 | 57 | def get_user(username: str): 58 | try: 59 | _user = session.execute(f"SELECT user_name, hashed_password, disabled From user WHERE user_name='{username}'").one() 60 | if _user: 61 | return UserInDB(username=_user[0], disable=_user[2], hashed_password=_user[1]) 62 | except TypeError or IndexError: 63 | return False 64 | 65 | 66 | # This function will verify the user credentials... 67 | def authenticate_user(username: str, password: str): 68 | _user = get_user(username) 69 | if not _user or not verify_password(password, _user.hashed_password): 70 | return False 71 | """if not verify_password(password, _user.hashed_password): 72 | return False""" 73 | return _user 74 | 75 | 76 | def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): 77 | to_encode = data.copy() 78 | expire = datetime.utcnow() + expires_delta 79 | to_encode.update({'exp': expire}) 80 | encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) 81 | return encoded_jwt 82 | 83 | 84 | async def get_current_user(token: str = Depends(oauth2_scheme)): 85 | try: 86 | payload = jwt.decode(token, SECRET_KEY, algorithms=ALGORITHM) 87 | username: str = payload.get("sub") 88 | if username is None: 89 | raise HTTP_401_UNAUTHORIZED 90 | except JWTError: 91 | raise HTTP_401_UNAUTHORIZED 92 | _user = get_user(username=username) 93 | if _user is None: 94 | raise HTTP_401_UNAUTHORIZED 95 | return _user 96 | 97 | 98 | async def get_current_active_user(current_user: User = Depends(get_current_user)): 99 | if current_user.disable: # if disable == True(i.e user id not active then raise inactive user flag) 100 | raise HTTPException(status_code=403, detail="Inactive user") 101 | return {"username": current_user.username} 102 | 103 | 104 | # To generate a new token after logging in 105 | @router.post("/get_token", tags=["users"], status_code=status.HTTP_200_OK) 106 | async def login(form_data: OAuth2PasswordRequestForm = Depends()): 107 | _user = authenticate_user(form_data.username, form_data.password) # Verify the credentials 108 | if not _user: 109 | raise HTTPException(status_code=403, detail="Incorrect Username or Password", headers={"WWW-Authenticate": "Bearer"}) 110 | access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) 111 | 112 | # Create an access token with data containing username of the user and the expiry time of the token 113 | access_token = create_access_token( 114 | data={"sub": _user.username}, expires_delta=access_token_expires 115 | ) 116 | # _user = await get_current_user(access_token) 117 | is_active = False if _user.disable else True 118 | return {"access_token": access_token, "token_type": "bearer", "is_active":is_active} 119 | -------------------------------------------------------------------------------- /cassandra/node1/cassandra/jvm11-server.options: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # jvm11-server.options # 3 | # # 4 | # See jvm-server.options. This file is specific for Java 11 and newer. # 5 | ########################################################################### 6 | 7 | ################# 8 | # GC SETTINGS # 9 | ################# 10 | 11 | 12 | 13 | ### CMS Settings 14 | -XX:+UseConcMarkSweepGC 15 | -XX:+CMSParallelRemarkEnabled 16 | -XX:SurvivorRatio=8 17 | -XX:MaxTenuringThreshold=1 18 | -XX:CMSInitiatingOccupancyFraction=75 19 | -XX:+UseCMSInitiatingOccupancyOnly 20 | -XX:CMSWaitDuration=10000 21 | -XX:+CMSParallelInitialMarkEnabled 22 | -XX:+CMSEdenChunksRecordAlways 23 | ## some JVMs will fill up their heap when accessed via JMX, see CASSANDRA-6541 24 | -XX:+CMSClassUnloadingEnabled 25 | 26 | 27 | 28 | ### G1 Settings 29 | ## Use the Hotspot garbage-first collector. 30 | #-XX:+UseG1GC 31 | #-XX:+ParallelRefProcEnabled 32 | 33 | # 34 | ## Have the JVM do less remembered set work during STW, instead 35 | ## preferring concurrent GC. Reduces p99.9 latency. 36 | #-XX:G1RSetUpdatingPauseTimePercent=5 37 | # 38 | ## Main G1GC tunable: lowering the pause target will lower throughput and vise versa. 39 | ## 200ms is the JVM default and lowest viable setting 40 | ## 1000ms increases throughput. Keep it smaller than the timeouts in cassandra.yaml. 41 | #-XX:MaxGCPauseMillis=500 42 | 43 | ## Optional G1 Settings 44 | # Save CPU time on large (>= 16GB) heaps by delaying region scanning 45 | # until the heap is 70% full. The default in Hotspot 8u40 is 40%. 46 | #-XX:InitiatingHeapOccupancyPercent=70 47 | 48 | # For systems with > 8 cores, the default ParallelGCThreads is 5/8 the number of logical cores. 49 | # Otherwise equal to the number of cores when 8 or less. 50 | # Machines with > 10 cores should try setting these to <= full cores. 51 | #-XX:ParallelGCThreads=16 52 | # By default, ConcGCThreads is 1/4 of ParallelGCThreads. 53 | # Setting both to the same value can reduce STW durations. 54 | #-XX:ConcGCThreads=16 55 | 56 | 57 | ### JPMS 58 | 59 | -Djdk.attach.allowAttachSelf=true 60 | --add-exports java.base/jdk.internal.misc=ALL-UNNAMED 61 | --add-exports java.base/jdk.internal.ref=ALL-UNNAMED 62 | --add-exports java.base/sun.nio.ch=ALL-UNNAMED 63 | --add-exports java.management.rmi/com.sun.jmx.remote.internal.rmi=ALL-UNNAMED 64 | --add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED 65 | --add-exports java.rmi/sun.rmi.server=ALL-UNNAMED 66 | --add-exports java.sql/java.sql=ALL-UNNAMED 67 | 68 | --add-opens java.base/java.lang.module=ALL-UNNAMED 69 | --add-opens java.base/jdk.internal.loader=ALL-UNNAMED 70 | --add-opens java.base/jdk.internal.ref=ALL-UNNAMED 71 | --add-opens java.base/jdk.internal.reflect=ALL-UNNAMED 72 | --add-opens java.base/jdk.internal.math=ALL-UNNAMED 73 | --add-opens java.base/jdk.internal.module=ALL-UNNAMED 74 | --add-opens java.base/jdk.internal.util.jar=ALL-UNNAMED 75 | --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED 76 | 77 | 78 | ### GC logging options -- uncomment to enable 79 | 80 | # Java 11 (and newer) GC logging options: 81 | # See description of https://bugs.openjdk.java.net/browse/JDK-8046148 for details about the syntax 82 | # The following is the equivalent to -XX:+PrintGCDetails -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=10M 83 | #-Xlog:gc=info,heap*=trace,age*=debug,safepoint=info,promotion*=trace:file=/var/log/cassandra/gc.log:time,uptime,pid,tid,level:filecount=10,filesize=10485760 84 | 85 | # Notes for Java 8 migration: 86 | # 87 | # -XX:+PrintGCDetails maps to -Xlog:gc*:... - i.e. add a '*' after "gc" 88 | # -XX:+PrintGCDateStamps maps to decorator 'time' 89 | # 90 | # -XX:+PrintHeapAtGC maps to 'heap' with level 'trace' 91 | # -XX:+PrintTenuringDistribution maps to 'age' with level 'debug' 92 | # -XX:+PrintGCApplicationStoppedTime maps to 'safepoint' with level 'info' 93 | # -XX:+PrintPromotionFailure maps to 'promotion' with level 'trace' 94 | # -XX:PrintFLSStatistics=1 maps to 'freelist' with level 'trace' 95 | 96 | ### Netty Options 97 | 98 | # On Java >= 9 Netty requires the io.netty.tryReflectionSetAccessible system property to be set to true to enable 99 | # creation of direct buffers using Unsafe. Without it, this falls back to ByteBuffer.allocateDirect which has 100 | # inferior performance and risks exceeding MaxDirectMemory 101 | -Dio.netty.tryReflectionSetAccessible=true 102 | 103 | # The newline in the end of file is intentional 104 | -------------------------------------------------------------------------------- /cassandra/node1/cassandra/logback.xml: -------------------------------------------------------------------------------- 1 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | INFO 35 | 36 | ${cassandra.logdir}/system.log 37 | 38 | 39 | ${cassandra.logdir}/system.log.%d{yyyy-MM-dd}.%i.zip 40 | 41 | 50MB 42 | 7 43 | 5GB 44 | 45 | 46 | %-5level [%thread] %date{ISO8601} %F:%L - %msg%n 47 | 48 | 49 | 50 | 51 | 52 | 53 | ${cassandra.logdir}/debug.log 54 | 55 | 56 | ${cassandra.logdir}/debug.log.%d{yyyy-MM-dd}.%i.zip 57 | 58 | 50MB 59 | 7 60 | 5GB 61 | 62 | 63 | %-5level [%thread] %date{ISO8601} %F:%L - %msg%n 64 | 65 | 66 | 67 | 68 | 69 | 70 | 1024 71 | 0 72 | true 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | INFO 81 | 82 | 83 | %-5level [%thread] %date{ISO8601} %F:%L - %msg%n 84 | 85 | 86 | 87 | 90 | 93 | 94 | 95 | 96 | 104 | 105 | 106 | 109 | 110 | 113 | 114 | 115 | 116 | 117 | 118 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /frontend/src/Mycomponents/pages/signuppages/login.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { Navigate } from 'react-router-dom'; 3 | import axios from 'axios'; 4 | import Nav from "../components/nav"; 5 | import Footer from "../components/footer" 6 | 7 | 8 | const Login = () => { 9 | let mystyle = { 10 | marginTop: "130px", 11 | marginBottom: "220px", 12 | maxWidth: "500px" 13 | } 14 | 15 | const [usernameReg, setusernameReg] = useState(''); 16 | const [username, setUsername] = useState(''); 17 | const [passWord, setpassword] = useState(''); 18 | const [usernameerror, setUsernamerror] = useState(); 19 | const [passworderror, setPassworderror] = useState(); 20 | const [loading, setLoading] = useState(false); 21 | const [redirectuser, setRedirectuser] = useState(false); 22 | const [redirectverify, setRedirectverify] = useState(false); 23 | const [statuscodeError, setStatuscodeerror] = useState(); 24 | 25 | 26 | let button = usernameerror === false && passworderror === false; 27 | 28 | const loginClick = async (e) => { 29 | e.preventDefault(); 30 | setLoading(true); 31 | await axios({ 32 | url: "get_token", 33 | method: "POST", 34 | data: 'grant_type=password&username=' + username + '&password=' + passWord, 35 | headers: { 36 | 'Accept': 'application/json', 37 | 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8;application/json', 38 | 'Access-Control-Allow-Origin': '*', 39 | 'withCredentials': 'true' 40 | } 41 | }).then((resp) => { 42 | setLoading(false); 43 | localStorage.setItem("token", resp.data.access_token) 44 | localStorage.setItem("active", resp.data.is_active) 45 | if (resp.data.is_active === true) { 46 | setRedirectuser(true); 47 | } 48 | else if (resp.data.is_active === false) { 49 | setRedirectverify(true); 50 | } 51 | }) 52 | .catch((error) => { 53 | setLoading(false); 54 | if (error.response.status === 403) { 55 | setStatuscodeerror(true) 56 | } 57 | }) 58 | 59 | 60 | } 61 | if (redirectuser) { 62 | return 63 | } 64 | if (redirectverify) { 65 | return 66 | } 67 | const PassWordHandler = (e) => { 68 | const Pass = e.target.value; 69 | setpassword(Pass); 70 | if (Pass === '') { 71 | setPassworderror(true); 72 | } 73 | else { 74 | setPassworderror(false); 75 | } 76 | 77 | } 78 | const usernameHandler = (e) => { 79 | const Name = e.target.value; 80 | setusernameReg(Name); 81 | const NameValue = Name.toLowerCase() 82 | setUsername(NameValue) 83 | if (Name === '') { 84 | setUsernamerror(true); 85 | } 86 | else { 87 | setUsernamerror(false); 88 | } 89 | 90 | } 91 | 92 | return ( 93 | <> 94 |