├── Dockerfile ├── LICENSE ├── README.md ├── Tiredful-API.jpg ├── Tiredful-API ├── Tiredful_API │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── advertisements │ ├── __init__.py │ ├── apps.py │ ├── models.py │ ├── serializers.py │ ├── templates │ │ └── advertisements │ │ │ └── index.html │ ├── urls.py │ └── views.py ├── blog │ ├── __init__.py │ ├── apps.py │ ├── models.py │ ├── permissions.py │ ├── serializers.py │ ├── templates │ │ └── blog │ │ │ └── index.html │ ├── urls.py │ └── views.py ├── client_cred.txt ├── db.sqlite3 ├── exams │ ├── __init__.py │ ├── apps.py │ ├── models.py │ ├── serializers.py │ ├── templates │ │ └── exams │ │ │ └── index.html │ ├── urls.py │ └── views.py ├── health │ ├── __init__.py │ ├── apps.py │ ├── models.py │ ├── serializers.py │ ├── templates │ │ └── health │ │ │ └── index.html │ ├── urls.py │ └── views.py ├── intro │ ├── __init__.py │ ├── apps.py │ ├── forms.py │ ├── models.py │ ├── templates │ │ └── intro │ │ │ ├── about.html │ │ │ ├── csrf.html │ │ │ ├── index.html │ │ │ ├── scenarios.html │ │ │ └── token.html │ ├── urls.py │ └── views.py ├── library │ ├── __init__.py │ ├── apps.py │ ├── models.py │ ├── serializers.py │ ├── templates │ │ └── library │ │ │ └── index.html │ ├── urls.py │ └── views.py ├── manage.py ├── static │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ ├── js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── npm.js │ └── rest_framework │ │ ├── css │ │ ├── bootstrap-tweaks.css │ │ ├── bootstrap.min.css │ │ ├── default.css │ │ └── prettify.css │ │ ├── docs │ │ ├── css │ │ │ ├── base.css │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap.min.css │ │ │ ├── font-awesome-4.0.3.css │ │ │ ├── highlight.css │ │ │ └── jquery.json-view.min.css │ │ ├── fonts │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ ├── img │ │ │ ├── favicon.ico │ │ │ └── grid.png │ │ └── js │ │ │ ├── api.js │ │ │ ├── base.js │ │ │ ├── bootstrap.min.js │ │ │ ├── highlight.pack.js │ │ │ ├── jquery-1.10.2.min.js │ │ │ └── jquery.json-view.min.js │ │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ │ ├── img │ │ ├── glyphicons-halflings-white.png │ │ ├── glyphicons-halflings.png │ │ └── grid.png │ │ └── js │ │ ├── ajax-form.js │ │ ├── bootstrap.min.js │ │ ├── coreapi-0.1.0.js │ │ ├── csrf.js │ │ ├── default.js │ │ ├── jquery-1.12.4.min.js │ │ └── prettify-min.js ├── templates │ ├── basic.html │ ├── elements │ │ ├── css-content.html │ │ ├── javascript-content.html │ │ ├── navbar.html │ │ └── sidebar.html │ └── scenario-basic.html └── trains │ ├── __init__.py │ ├── apps.py │ ├── models.py │ ├── serializers.py │ ├── templates │ └── trains │ │ └── index.html │ ├── urls.py │ └── views.py └── requirements.txt /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.6 2 | MAINTAINER jsvazic@gmail.com 3 | 4 | COPY . /app/ 5 | 6 | RUN apk add --update \ 7 | python \ 8 | python-dev \ 9 | py-pip \ 10 | build-base \ 11 | && rm -rf /var/cache/apk/* \ 12 | && /usr/bin/pip install -r /app/requirements.txt 13 | 14 | WORKDIR /app/Tiredful-API 15 | 16 | EXPOSE 8000 17 | 18 | CMD ["/usr/bin/python", "manage.py", "runserver", "0.0.0.0:8000"] 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### What is Tiredful API? 2 | 3 | Tiredful API is intentionally designed broken app. The aim of this web app is to teach developers, QA or security professionals about flaws present in webservices (REST API) due to insecure coding practice. 4 | 5 |  6 | 7 | ### Who can use Tiredful API? 8 | * Web developers 9 | * Web Pentesters 10 | * Security Professionals 11 | * Student 12 | 13 | ### What is included in Tiredful API? 14 | 15 | I tried to cover most of the vulnerabilities, I am sure that we have missed some vulnerabilities.Please ping me if you know any good vulnerability that should be included. For now I have included following vulnerabilities. 16 | 17 | * Information Disclosure 18 | * Insecure Direct Object Reference 19 | * Access Control 20 | * Throttling 21 | * SQL Injection (SQLite) 22 | * Cross Site Scripting. 23 | 24 | [You can see solution here](https://payatu.com/tiredful-api-solution/) 25 | 26 | ### Can I contribute? 27 | Yes, you can help by sending us the details of vulnerabilities that we can implement in future versions of Tiredful API. Please mail us at info[at]payatu.com with subject "Tiredful API Scenario". 28 | 29 | ### Where can I get Tiredful API? 30 | Source can be downloaded from [link](https://github.com/payatu/Tiredful-API). 31 | 32 | ### How to run Tiredful API? 33 | Tiredful API is developed using Django Framework and Django Rest Framework, so for running the web server user needs execute following command. 34 | 35 | * Navigate to the source folder and locate manage.py file. 36 | * Then execute `python manage.py runserver`. 37 | * If static files are not getting load, then execute above command with insecure flag i.e. `python manage.py runserver --insecure` 38 | If you are facing any issue starting the web server please refer [django documentation admin](https://docs.djangoproject.com/en/1.11/ref/django-admin/#runserver) or [django documentation tutorial](https://docs.djangoproject.com/en/1.11/intro/tutorial01/#the-development-server). 39 | Please ping me if you are still not able to run development server. 40 | 41 | **Note:** It is recommended to use required libraries with the version specified in the requirements.txt. Please refer [this](https://pip.pypa.io/en/stable/user_guide/#requirements-files) more details 42 | 43 | #### Docker Container 44 | You can run Tiredful via [Docker](https://www.docker.com). Simply execute: 45 | 46 | ``` 47 | docker build -t tiredful . 48 | docker run -p 8000:8000 --name tiredful -it tiredful 49 | ``` 50 | 51 | Browse to `http://localhost:8000/` and you are all set. Use `CTRL-C` to shut down the server. 52 | 53 | Added new JWT based scenarios. Updated repository available at [repo](https://github.com/siddharthbezalwar/Tiredful-API) 54 | 55 | #### Python3 Compatible Code 56 | [Tiredful API Python3](https://github.com/siddharthbezalwar/Tiredful-API-py3-beta) 57 | 58 | ### Feedback and Bug Reports. 59 | We would love to hear from you about your experience with Tiredful API. Please send us an email on info [at] payatu [dot] com or siddharth [dot] bezalwar [at] gmail [dot] com with Subject "Tiredful API Issue" based on what you want to share. Please include the below in your email. 60 | 61 | * Operating system with version. 62 | * Django Framework used. 63 | * Steps to replicate issue. 64 | 65 | 66 | ### Author 67 | Siddharth Bezalwar 68 | 69 | @fattu_medjai | siddharth [dot] bezalwar [at] gmail [dot] com 70 | 71 | ### About Payatu 72 | Payatu is a boutique security testing company with specialization in: 73 | 74 | * IoT Security 75 | * Mobile Security 76 | * Cloud security 77 | * Web Security 78 | We also organize two International Security Conferences 79 | 80 | nullcon International Security Conference - http://nullcon.net 81 | hardwear.io Hardware Security Conference - http://hardwear.io 82 | **Website:** http://payatu.com **Email:** info (at) payatu dot com 83 | -------------------------------------------------------------------------------- /Tiredful-API.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API.jpg -------------------------------------------------------------------------------- /Tiredful-API/Tiredful_API/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | -------------------------------------------------------------------------------- /Tiredful-API/Tiredful_API/settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | """ 13 | Django settings for Tiredful_API project. 14 | 15 | Generated by 'django-admin startproject' using Django 1.11. 16 | 17 | For more information on this file, see 18 | https://docs.djangoproject.com/en/1.11/topics/settings/ 19 | 20 | For the full list of settings and their values, see 21 | https://docs.djangoproject.com/en/1.11/ref/settings/ 22 | """ 23 | 24 | import os 25 | 26 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 27 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 28 | 29 | # Quick-start development settings - unsuitable for production 30 | # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ 31 | 32 | # SECURITY WARNING: keep the secret key used in production secret! 33 | SECRET_KEY = 'han4v+at1&s0t4_h^g##ch@&w1b-kzf*drl166prl+*=m@e+zn' 34 | 35 | # SECURITY WARNING: don't run with debug turned on in production! 36 | DEBUG = True 37 | 38 | ALLOWED_HOSTS = ['*'] 39 | 40 | # Application definition 41 | 42 | INSTALLED_APPS = [ 43 | 'django.contrib.admin', 44 | 'django.contrib.auth', 45 | 'django.contrib.contenttypes', 46 | 'django.contrib.sessions', 47 | 'django.contrib.messages', 48 | 'django.contrib.staticfiles', 49 | 'oauth2_provider', 50 | 'rest_framework', 51 | 'intro.apps.IntroConfig', 52 | 'library.apps.LibraryConfig', 53 | 'exams.apps.ExamsConfig', 54 | 'blog.apps.BlogConfig', 55 | 'trains.apps.TrainsConfig', 56 | 'health.apps.HealthConfig', 57 | 'advertisements.apps.AdvertisementsConfig', 58 | ] 59 | 60 | MIDDLEWARE = [ 61 | 'django.middleware.security.SecurityMiddleware', 62 | 'django.contrib.sessions.middleware.SessionMiddleware', 63 | 'oauth2_provider.middleware.OAuth2TokenMiddleware', 64 | 'django.middleware.common.CommonMiddleware', 65 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 66 | 'django.contrib.messages.middleware.MessageMiddleware', 67 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 68 | ] 69 | 70 | ROOT_URLCONF = 'Tiredful_API.urls' 71 | 72 | TEMPLATES = [ 73 | { 74 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 75 | 'DIRS': ['templates'], 76 | 'APP_DIRS': True, 77 | 'OPTIONS': { 78 | 'context_processors': [ 79 | 'django.template.context_processors.debug', 80 | 'django.template.context_processors.request', 81 | 'django.contrib.auth.context_processors.auth', 82 | 'django.contrib.messages.context_processors.messages', 83 | 'django.template.context_processors.static', 84 | ], 85 | }, 86 | }, 87 | ] 88 | 89 | WSGI_APPLICATION = 'Tiredful_API.wsgi.application' 90 | 91 | # Database 92 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 93 | 94 | DATABASES = { 95 | 'default': { 96 | 'ENGINE': 'django.db.backends.sqlite3', 97 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 98 | } 99 | } 100 | 101 | # Password validation 102 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 103 | 104 | AUTH_PASSWORD_VALIDATORS = [ 105 | { 106 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 107 | }, 108 | { 109 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 110 | }, 111 | { 112 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 113 | }, 114 | { 115 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 116 | }, 117 | ] 118 | 119 | # Internationalization 120 | # https://docs.djangoproject.com/en/1.11/topics/i18n/ 121 | 122 | LANGUAGE_CODE = 'en-us' 123 | 124 | TIME_ZONE = 'UTC' 125 | 126 | USE_I18N = True 127 | 128 | USE_L10N = True 129 | 130 | USE_TZ = True 131 | 132 | # Static files (CSS, JavaScript, Images) 133 | # https://docs.djangoproject.com/en/1.11/howto/static-files/ 134 | 135 | STATIC_URL = '/static/' 136 | 137 | STATICFILES_DIRS = [ 138 | os.path.join(BASE_DIR, "static"), 139 | ] 140 | 141 | OAUTH2_PROVIDER = { 142 | # this is the list of available scopes 143 | 'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'} 144 | } 145 | 146 | # API Renderers 147 | REST_FRAMEWORK = { 148 | 'DEFAULT_RENDERER_CLASSES': ( 149 | 'rest_framework.renderers.JSONRenderer', 150 | ), 151 | 'DEFAULT_PARSER_CLASSES': ( 152 | 'rest_framework.parsers.JSONParser', 153 | ), 154 | 'DEFAULT_AUTHENTICATION_CLASSES': ( 155 | 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', 156 | ), 157 | 'DEFAULT_PERMISSION_CLASSES': ( 158 | 'rest_framework.permissions.AllowAny', 159 | ), 160 | 'DEFAULT_THROTTLE_RATES': { 161 | 'anon': '10/day', 162 | 'user': '20/hour', 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /Tiredful-API/Tiredful_API/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | """Tiredful_API URL Configuration 13 | 14 | The `urlpatterns` list routes URLs to views. For more information please see: 15 | https://docs.djangoproject.com/en/1.11/topics/http/urls/ 16 | Examples: 17 | Function views 18 | 1. Add an import: from my_app import views 19 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 20 | Class-based views 21 | 1. Add an import: from other_app.views import Home 22 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 23 | Including another URLconf 24 | 1. Import the include() function: from django.conf.urls import url, include 25 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 26 | """ 27 | from django.conf.urls import url, include 28 | from django.contrib.auth.models import User, Group 29 | 30 | from rest_framework import permissions, routers, serializers, viewsets 31 | 32 | 33 | # first we define the serializers 34 | class UserSerializer(serializers.ModelSerializer): 35 | class Meta: 36 | model = User 37 | 38 | 39 | class GroupSerializer(serializers.ModelSerializer): 40 | class Meta: 41 | model = Group 42 | 43 | 44 | urlpatterns = [ 45 | # URL for user login 46 | url(r'^oauth/', include('oauth2_provider.urls', namespace='oauth2_provider')), 47 | 48 | # URL for including intro app. 49 | url(r'', include('intro.urls', namespace="intro")), 50 | 51 | # URL for including library app 52 | url(r'^api/v1/', include('library.urls', namespace="library-api")), 53 | url(r'^library/', include('library.urls', namespace="library")), 54 | 55 | # URL for including exams app 56 | url(r'^api/v1/', include('exams.urls', namespace="exams-api")), 57 | url(r'^exams/', include('exams.urls', namespace="exams")), 58 | 59 | # URL for including blog app 60 | url(r'^api/v1/', include('blog.urls', namespace="blog-api")), 61 | url(r'^blog/', include('blog.urls', namespace="blog")), 62 | 63 | # URL for including trains app 64 | url(r'^api/v1/', include('trains.urls', namespace="trains-api")), 65 | url(r'^trains/', include('trains.urls', namespace="trains")), 66 | 67 | # URL for including health app 68 | url(r'^api/v1/', include('health.urls', namespace="health-api")), 69 | url(r'^health/', include('health.urls', namespace="health")), 70 | 71 | # URL for including advertisements app 72 | url(r'^api/v1/', include('advertisements.urls', namespace="advertisements-api")), 73 | url(r'^advertisements/', include('advertisements.urls', namespace="advertisements")), 74 | 75 | ] 76 | -------------------------------------------------------------------------------- /Tiredful-API/Tiredful_API/wsgi.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | """ 13 | WSGI config for Tiredful_API project. 14 | 15 | It exposes the WSGI callable as a module-level variable named ``application``. 16 | 17 | For more information on this file, see 18 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ 19 | """ 20 | 21 | import os 22 | 23 | from django.core.wsgi import get_wsgi_application 24 | 25 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Tiredful_API.settings") 26 | 27 | application = get_wsgi_application() 28 | -------------------------------------------------------------------------------- /Tiredful-API/advertisements/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | -------------------------------------------------------------------------------- /Tiredful-API/advertisements/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | from __future__ import unicode_literals 13 | 14 | from django.apps import AppConfig 15 | 16 | 17 | class AdvertisementsConfig(AppConfig): 18 | name = 'advertisements' 19 | -------------------------------------------------------------------------------- /Tiredful-API/advertisements/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | from __future__ import unicode_literals 13 | 14 | from django.db import models 15 | from django.contrib.auth.models import User 16 | 17 | 18 | # Advertisement Classfied 19 | class Classified(models.Model): 20 | headline = models.CharField(max_length=150) 21 | info = models.CharField(max_length=2048, default="") 22 | price = models.DecimalField(max_digits=7, decimal_places=2) 23 | user = models.ForeignKey(User, default=1) 24 | -------------------------------------------------------------------------------- /Tiredful-API/advertisements/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | from rest_framework import serializers 13 | 14 | from advertisements.models import Classified 15 | 16 | 17 | # Classfied object serializer 18 | class ClassifiedSerializers(serializers.ModelSerializer): 19 | class Meta: 20 | model = Classified 21 | fields = ('headline', 'info', 'price', 'user') 22 | -------------------------------------------------------------------------------- /Tiredful-API/advertisements/templates/advertisements/index.html: -------------------------------------------------------------------------------- 1 | 11 | 12 | {% extends 'scenario-basic.html' %} 13 | 14 | {% block title-text %} Tiredful API: Cross Site Scripting {% endblock %} 15 | 16 | {% block content %} 17 |
19 | An advertisement portal where user can post and see classified advts.
20 | APIs are implemented for accessing the list of classified advertisements and to create the advertisements.
21 | Following are the API end points:
22 | 1. List of advertisements (authentication required)
23 |
24 | GET Method http://{{ request.get_host }}/api/v1/advertisements/ 25 |26 | 2. To create a advertisement (authentication required) 27 |
28 | POST http://{{ request.get_host }}/api/v1/advertisements/ 29 |30 | POST: 31 |
32 | { 33 | "headline": <headline(string)>, 34 | "info": <info(string)>, 35 | "price": <price(float(7,2))> 36 | } 37 |38 | 39 | Aim: Find parameters accepting cross site scripting meta-characters. 40 | 41 | {% endblock %} 42 | -------------------------------------------------------------------------------- /Tiredful-API/advertisements/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | from django.conf.urls import url 13 | from . import views 14 | 15 | urlpatterns = [ 16 | 17 | # ex: /advertisements/ 18 | url(r'^$', views.index, name='index'), 19 | 20 | # ex: /advertisements/ (api) 21 | url(r'^advertisements/$', views.advts, name='advertisements'), 22 | ] 23 | -------------------------------------------------------------------------------- /Tiredful-API/advertisements/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | from __future__ import unicode_literals 13 | 14 | from django.shortcuts import render 15 | from django.contrib.auth.decorators import login_required 16 | from django.contrib.auth.models import User 17 | 18 | from rest_framework import status 19 | from rest_framework.decorators import api_view, permission_classes 20 | from rest_framework.permissions import IsAuthenticated 21 | from rest_framework.response import Response 22 | 23 | from advertisements.models import Classified 24 | from advertisements.serializers import ClassifiedSerializers 25 | 26 | 27 | # Index for cross site scripting 28 | def index(request): 29 | """ 30 | Index for cross site scripting 31 | """ 32 | return render(request, 'advertisements/index.html', ) 33 | 34 | 35 | @api_view(['GET', 'POST']) 36 | @permission_classes((IsAuthenticated,)) 37 | def advts(request): 38 | """ 39 | List of advts posted 40 | """ 41 | if request.method == 'GET': 42 | classifieds = Classified.objects.all() 43 | serializer = ClassifiedSerializers(classifieds, many=True) 44 | return Response(serializer.data) 45 | elif request.method == 'POST': 46 | serializer = ClassifiedSerializers(data=request.data) 47 | serializer.initial_data['user'] = request.user.id 48 | if serializer.is_valid(): 49 | serializer.save() 50 | return Response(serializer.data, status=status.HTTP_201_CREATED) 51 | return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 52 | else: 53 | return Response( 54 | serializer.errors, status=status.HTTP_400_BAD_REQUEST) 55 | -------------------------------------------------------------------------------- /Tiredful-API/blog/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | -------------------------------------------------------------------------------- /Tiredful-API/blog/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | from __future__ import unicode_literals 13 | 14 | from django.apps import AppConfig 15 | 16 | 17 | class BlogConfig(AppConfig): 18 | name = 'blog' 19 | -------------------------------------------------------------------------------- /Tiredful-API/blog/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | from __future__ import unicode_literals 13 | 14 | from django.db import models 15 | from django.contrib.auth.models import User 16 | 17 | 18 | class Article(models.Model): 19 | title = models.CharField(max_length=40) 20 | content = models.TextField() 21 | approval_status = models.BooleanField() 22 | user = models.ForeignKey(User) 23 | -------------------------------------------------------------------------------- /Tiredful-API/blog/permissions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | from rest_framework import permissions 13 | 14 | 15 | class UserPermission(permissions.BasePermission): 16 | def has_permission(self, request, view): 17 | if request.method in permissions.SAFE_METHODS: 18 | return True 19 | elif request.method == 'DELETE': 20 | return True 21 | else: 22 | return False 23 | 24 | def has_object_permission(self, request, view, obj): 25 | if request.method in permissions.SAFE_METHODS: 26 | return True 27 | elif request.method == 'DELETE': 28 | return True 29 | else: 30 | return False 31 | -------------------------------------------------------------------------------- /Tiredful-API/blog/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | from rest_framework import serializers 13 | 14 | from blog.models import Article 15 | from django.contrib.auth.models import User 16 | 17 | 18 | # User object serializer 19 | class UserSerializer(serializers.ModelSerializer): 20 | class Meta: 21 | model = User 22 | fields = ('username', 'password') 23 | 24 | 25 | # ScoreCard object serializer 26 | class ArticleSerializer(serializers.ModelSerializer): 27 | class Meta: 28 | model = Article 29 | fields = ('title', 'content', 'user') 30 | -------------------------------------------------------------------------------- /Tiredful-API/blog/templates/blog/index.html: -------------------------------------------------------------------------------- 1 | 11 | 12 | {% extends 'scenario-basic.html' %} 13 | 14 | {% block title-text %} Tiredful API: Access Control {% endblock %} 15 | 16 | {% block content %} 17 |
19 | A blog application allows user to create,edit and view articles.
20 | Developer decided to implement web services, so for testing purpose developers provides access to two API end points
21 | 1) Article Viewing -
22 |
23 | GET method http://{{ request.get_host }}/api/v1/articles/<article-id>/ 24 |25 | 2) Article Approving (Admin only)- 26 |
27 | GET method http://{{ request.get_host }}/api/v1/approve-article/<article-id>/ 28 |29 | 30 | Following are available blogs 31 |
20 | An online exam portal provides an API to access the result of attempt exams by a student.
21 | Login with "batman" and try to access exam result of other user.
22 | Following are the exam-id of test attempted by batman
23 |
GET method http://{{ request.get_host }}/api/v1/exams/<exam_id>/29 | 30 | Aim: Try to access exam results of other user. 31 | 32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /Tiredful-API/exams/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __ 4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( ) 5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )( 6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__) 7 | # 8 | # 9 | # Copyright (C) 2017-2018 Payatu Software Labs 10 | # This file is part of Tiredful API application 11 | 12 | from django.conf.urls import url 13 | from . import views 14 | 15 | urlpatterns = [ 16 | 17 | # ex: /exams/ 18 | url(r'^$', views.index, name='index'), 19 | 20 | # ex: /exams/score_card> 21 | url(r'^exams/(?P
19 | APIs implemented to serve a fitness tracker mobile app, is used to check fitness activity in a month.
20 | Following is the API end point to access monthly fitness activity
21 |
POST http://{{ request.get_host }}/api/v1/activities/22 |
25 | { 26 | "month": <month(string)> 27 | } 28 |29 | 30 |
19 | This is not an actual challenge. A web application is vulnerable to CSRF, if it is storing the token generated by authentication scheme in a cookie.
20 |
For successful execution of CSRF attack, attacker needs a cookie which is used to identify the user. :)
21 |
Tiredful API is intentionally designed broken web app. The purpose of this application is to teach developers, QA or security professionals about flaws present in webservices (REST API) due to insecure coding practice.
20 |
21 |
22 | Let's Start
23 |
20 | TiredFul API is a web app intentionally developed to be insecure. 21 | The purpose of the app to teach developers, QA or security professionals about flaws present in webservices (REST API) due to insecure coding practice. 22 | Following are the scenarios implemented. 23 |
48 | All the APIs are accessed over HTTP. All the requests to the APIs should have ACCEPT
header.
49 |
56 | All the requests to the APIs using HTTP POST method should have Content-Type
header.
57 |
64 | Some of the challenges require authentication under an account with appropriate access. 65 | For accessing login protected data user needs to provide an access key. 66 | Process to obtain the access key is provided in User Token section of the web application. 67 |
68 |
19 | A library decided to provide services to other third party through its APIs.
20 | One of the implemented API is to get the details of the book by providing ISBN number.
21 | We suspect that the API is revealing interesting information apart from the book details
22 | Following is the API-end point for getting book details.
23 |
24 | GET method http://{{ request.get_host }}/api/v1/books/<ISBN>/ 25 |26 | Following are the book ISBNs available: 27 | {% if books %} 28 |
to respect formatting
19 | }
20 |
21 | .main-container {
22 | padding-left: 30px;
23 | padding-right: 30px;
24 | }
25 |
26 | .btn:focus,
27 | .btn:focus:active {
28 | outline: none;
29 | }
30 |
31 | .sidebar {
32 | overflow: auto;
33 | font-family: verdana;
34 | font-size: 12px;
35 | font-weight: 200;
36 | background-color: #2e353d;
37 | position: fixed;
38 | top: 0px;
39 | width: 225px;
40 | height: 100%;
41 | color: #FFF;
42 | }
43 |
44 | .sidebar .brand {
45 | background-color: #23282e;
46 | display: block;
47 | text-align: center;
48 | padding: 25px 0;
49 | margin-top: 0;
50 | margin-bottom: 0;
51 | }
52 |
53 | .sidebar .brand a {
54 | color: #FFF;
55 | }
56 |
57 | .sidebar .brand a:hover,
58 | .sidebar .brand a:active,
59 | .sidebar .brand a:focus {
60 | text-decoration: none;
61 | }
62 |
63 | .sidebar .toggle-btn {
64 | display: none;
65 | }
66 |
67 | .sidebar .menu-list ul,
68 | .sidebar .menu-list li {
69 | background: #2e353d;
70 | list-style: none;
71 | padding: 0px;
72 | margin: 0px;
73 | line-height: 35px;
74 | cursor: pointer;
75 | }
76 |
77 | .sidebar .menu-list ul :not(collapsed) .arrow:before,
78 | .sidebar .menu-list li :not(collapsed) .arrow:before {
79 | font-family: FontAwesome;
80 | content: "\f078";
81 | display: inline-block;
82 | padding-left: 10px;
83 | padding-right: 10px;
84 | vertical-align: middle;
85 | float: right;
86 | }
87 |
88 | .sidebar .menu-list ul .active,
89 | .sidebar .menu-list li .active {
90 | border-left: 3px solid #d19b3d;
91 | background-color: #4f5b69;
92 | }
93 |
94 | .sidebar .menu-list ul .sub-menu li.active,
95 | .sidebar .menu-list li .sub-menu li.active {
96 | color: #d19b3d;
97 | }
98 |
99 | .sidebar .menu-list ul .sub-menu li.active a,
100 | .sidebar .menu-list li .sub-menu li.active a {
101 | color: #d19b3d;
102 | }
103 |
104 | .sidebar .menu-list ul .sub-menu li,
105 | .sidebar .menu-list li .sub-menu li {
106 | background-color: #181c20;
107 | border: none;
108 | border-bottom: 1px solid #23282e;
109 | margin-left: 0px;
110 | text-indent: 10px;
111 | }
112 |
113 | .sidebar .menu-list ul .sub-menu li:hover,
114 | .sidebar .menu-list li .sub-menu li:hover {
115 | background-color: #020203;
116 | }
117 |
118 |
119 | .sidebar .menu-list ul .sub-menu li a,
120 | .sidebar .menu-list li .sub-menu li a {
121 | display: block;
122 | }
123 |
124 | .sidebar .menu-list ul .sub-menu li a:before,
125 | .sidebar .menu-list li .sub-menu li a:before {
126 | font-family: FontAwesome;
127 | content: "\f105";
128 | display: inline-block;
129 | padding-left: 10px;
130 | padding-right: 10px;
131 | vertical-align: middle;
132 | }
133 |
134 | .sidebar .menu-list li {
135 | padding-left: 0px;
136 | border-left: 3px solid #2e353d;
137 | border-bottom: 1px solid #23282e;
138 | }
139 |
140 | .sidebar .menu-list li a {
141 | text-decoration: none;
142 | color: white;
143 | }
144 |
145 | .sidebar .menu-list li a i {
146 | padding-left: 10px;
147 | width: 20px;
148 | padding-right: 20px;
149 | }
150 |
151 | .sidebar .menu-list li:hover {
152 | border-left: 3px solid #d19b3d;
153 | background-color: #4f5b69;
154 | -webkit-transition: all 1s ease;
155 | -moz-transition: all 1s ease;
156 | -o-transition: all 1s ease;
157 | -ms-transition: all 1s ease;
158 | transition: all 1s ease;
159 | }
160 |
161 | body {
162 | margin: 0px;
163 | padding: 0px;
164 | }
165 |
166 | .coredocs-section-title {
167 | margin-top: 20px;
168 | padding-bottom: 10px;
169 | border-bottom: 1px solid lightgrey;
170 | }
171 |
172 | .coredocs-link-title a,
173 | .coredocs-section-title a {
174 | display: none;
175 | }
176 |
177 | .coredocs-link-title a,
178 | .coredocs-section-title a {
179 | text-decoration: none;
180 | }
181 |
182 | .coredocs-link-title:hover a,
183 | .coredocs-section-title:hover a {
184 | display: inline;
185 | font-size: 20px;
186 | }
187 |
188 | .coredocs-section-title:last-child {
189 | margin-top: 0;
190 | }
191 |
192 |
193 | /* @group Language Switcher */
194 |
195 | .sidebar .menu-list.menu-list-bottom {
196 | margin-bottom: 0;
197 | position: absolute;
198 | bottom: 0;
199 | left: 0;
200 | right: 0;
201 | border-top: 1px solid #23282e;
202 | }
203 |
204 | .sidebar .menu-list-bottom li span {
205 | float: right;
206 | margin-right: 20px;
207 | color: #d19b3d;
208 | }
209 |
210 | /* @end Language Switcher */
211 |
212 |
213 | /* @group Docs Content */
214 |
215 | .docs-content .meta .label {
216 | vertical-align: middle;
217 | font-size: 14px;
218 | font-weight: normal;
219 | }
220 |
221 | .docs-content .meta code {
222 | vertical-align: middle;
223 | padding: .2em .6em .3em;
224 | font-size: 14px;
225 | }
226 |
227 | .docs-content .btn {
228 | font-size: inherit;
229 | }
230 |
231 | .code-samples pre {
232 | margin-top: 20px;
233 | }
234 |
235 | /* @end Docs Content */
236 |
237 |
238 | @media (max-width: 767px) {
239 | .main-container {
240 | padding-left: 15px;
241 | padding-right: 15px;
242 | }
243 |
244 | .sidebar {
245 | position: relative;
246 | width: 100%;
247 | margin-bottom: 10px;
248 | overflow: visible;
249 | }
250 |
251 | .sidebar .toggle-btn {
252 | display: block;
253 | cursor: pointer;
254 | position: absolute;
255 | right: 10px;
256 | top: 10px;
257 | z-index: 10 !important;
258 | padding: 3px;
259 | width: 40px;
260 | text-align: center;
261 | }
262 |
263 | .sidebar .menu-list.menu-list-bottom {
264 | position: static;
265 | }
266 |
267 | .sidebar .brand {
268 | margin-top: 0;
269 | margin-bottom: 0;
270 |
271 | text-align: left !important;
272 | font-size: 22px;
273 | padding: 0;
274 | padding-left: 20px;
275 | line-height: 50px !important;
276 | }
277 | }
278 |
279 | @media (min-width: 767px) {
280 | .sidebar .menu-list .menu-content {
281 | display: block;
282 | }
283 | #main {
284 | width:calc(100% - 225px);
285 | float: right;
286 | }
287 | }
288 |
289 | @media (min-width: 992px) {
290 | .modal-lg {
291 | width: 980px;
292 | }
293 | }
294 |
295 | .api-modal .modal-title .fa {
296 | color: #93c54b;
297 | }
298 |
299 | .api-modal .modal-body .request-awaiting {
300 | padding: 35px 10px;
301 | color: #7F8177;
302 | text-align: center;
303 | }
304 |
305 | .api-modal .modal-body .meta {
306 | margin-bottom: 20px;
307 | }
308 |
309 | .api-modal .modal-body .meta .label {
310 | vertical-align: middle;
311 | font-size: 14px;
312 | font-weight: normal;
313 | }
314 |
315 | .api-modal .modal-body .meta code {
316 | vertical-align: middle;
317 | padding: .2em .6em .3em;
318 | font-size: 14px;
319 | }
320 |
321 | .api-modal .modal-content .toggle-view {
322 | text-align: right;
323 | float: right;
324 | }
325 |
326 | .api-modal .modal-content .response .well {
327 | margin: 0;
328 | max-height: 550px;
329 | }
330 |
331 | .highlight {
332 | background-color: #f7f7f9
333 | }
334 |
335 | .checkbox label.control-label {
336 | font-weight: bold
337 | }
338 |
339 | @media (min-width: 768px) {
340 | .navbar-nav.navbar-right:last-child {
341 | margin-right: 0 !important;
342 | }
343 | }
344 |
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/css/highlight.css:
--------------------------------------------------------------------------------
1 | /*
2 | This is the GitHub theme for highlight.js
3 |
4 | github.com style (c) Vasily Polovnyov
5 |
6 | */
7 |
8 | .hljs {
9 | display: block;
10 | overflow-x: auto;
11 | padding: 0.5em;
12 | color: #333;
13 | -webkit-text-size-adjust: none;
14 | }
15 |
16 | .hljs-comment,
17 | .diff .hljs-header,
18 | .hljs-javadoc {
19 | color: #998;
20 | font-style: italic;
21 | }
22 |
23 | .hljs-keyword,
24 | .css .rule .hljs-keyword,
25 | .hljs-winutils,
26 | .nginx .hljs-title,
27 | .hljs-subst,
28 | .hljs-request,
29 | .hljs-status {
30 | color: #333;
31 | font-weight: bold;
32 | }
33 |
34 | .hljs-number,
35 | .hljs-hexcolor,
36 | .ruby .hljs-constant {
37 | color: #008080;
38 | }
39 |
40 | .hljs-string,
41 | .hljs-tag .hljs-value,
42 | .hljs-phpdoc,
43 | .hljs-dartdoc,
44 | .tex .hljs-formula {
45 | color: #d14;
46 | }
47 |
48 | .hljs-title,
49 | .hljs-id,
50 | .scss .hljs-preprocessor {
51 | color: #900;
52 | font-weight: bold;
53 | }
54 |
55 | .hljs-list .hljs-keyword,
56 | .hljs-subst {
57 | font-weight: normal;
58 | }
59 |
60 | .hljs-class .hljs-title,
61 | .hljs-type,
62 | .vhdl .hljs-literal,
63 | .tex .hljs-command {
64 | color: #458;
65 | font-weight: bold;
66 | }
67 |
68 | .hljs-tag,
69 | .hljs-tag .hljs-title,
70 | .hljs-rule .hljs-property,
71 | .django .hljs-tag .hljs-keyword {
72 | color: #000080;
73 | font-weight: normal;
74 | }
75 |
76 | .hljs-attribute,
77 | .hljs-variable,
78 | .lisp .hljs-body,
79 | .hljs-name {
80 | color: #008080;
81 | }
82 |
83 | .hljs-regexp {
84 | color: #009926;
85 | }
86 |
87 | .hljs-symbol,
88 | .ruby .hljs-symbol .hljs-string,
89 | .lisp .hljs-keyword,
90 | .clojure .hljs-keyword,
91 | .scheme .hljs-keyword,
92 | .tex .hljs-special,
93 | .hljs-prompt {
94 | color: #990073;
95 | }
96 |
97 | .hljs-built_in {
98 | color: #0086b3;
99 | }
100 |
101 | .hljs-preprocessor,
102 | .hljs-pragma,
103 | .hljs-pi,
104 | .hljs-doctype,
105 | .hljs-shebang,
106 | .hljs-cdata {
107 | color: #999;
108 | font-weight: bold;
109 | }
110 |
111 | .hljs-deletion {
112 | background: #fdd;
113 | }
114 |
115 | .hljs-addition {
116 | background: #dfd;
117 | }
118 |
119 | .diff .hljs-change {
120 | background: #0086b3;
121 | }
122 |
123 | .hljs-chunk {
124 | color: #aaa;
125 | }
126 |
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/css/jquery.json-view.min.css:
--------------------------------------------------------------------------------
1 | .json-view{position:relative}
2 | .json-view .collapser{width:20px;height:18px;display:block;position:absolute;left:-1.7em;top:-.2em;z-index:5;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAD1JREFUeNpiYGBgOADE%2F3Hgw0DM4IRHgSsDFOzFInmMAQnY49ONzZRjDFiADT7dMLALiE8y4AGW6LoBAgwAuIkf%2F%2FB7O9sAAAAASUVORK5CYII%3D);background-repeat:no-repeat;background-position:center center;opacity:.5;cursor:pointer}
3 | .json-view .collapsed{-ms-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-khtml-transform:rotate(-90deg);-webkit-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}
4 | .json-view .bl{display:block;padding-left:20px;margin-left:-20px;position:relative}
5 | .json-view{font-family:monospace}
6 | .json-view ul{list-style-type:none;padding-left:2em;border-left:1px dotted;margin:.3em}
7 | .json-view ul li{position:relative}
8 | .json-view .comments,.json-view .dots{display:none;-moz-user-select:none;-ms-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}
9 | .json-view .comments{padding-left:.8em;font-style:italic;color:#888}
10 | .json-view .bool,.json-view .null,.json-view .num,.json-view .undef{font-weight:700;color:#1A01CC}
11 | .json-view .str{color:#800}
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/docs/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/docs/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/docs/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/docs/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/docs/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/docs/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/docs/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/docs/img/favicon.ico
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/img/grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/docs/img/grid.png
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/js/api.js:
--------------------------------------------------------------------------------
1 | function normalizeHTTPHeader (str) {
2 | // Capitalize HTTP headers for display.
3 | return (str.charAt(0).toUpperCase() + str.substring(1))
4 | .replace(/-(.)/g, function ($1) { return $1.toUpperCase() })
5 | .replace(/(Www)/g, function ($1) { return 'WWW' })
6 | .replace(/(Xss)/g, function ($1) { return 'XSS' })
7 | .replace(/(Md5)/g, function ($1) { return 'MD5' })
8 | }
9 |
10 | var responseDisplay = 'data'
11 | const coreapi = window.coreapi
12 | const schema = window.schema
13 |
14 | // Language Control
15 | $('#language-control li').click(function (event) {
16 | event.preventDefault();
17 | const languageMenuItem = $(this).find('a');
18 | var language = languageMenuItem.data("language")
19 |
20 | var languageControls = $(this).closest('ul').find('li');
21 | languageControls.find('a').not('[data-language="' + language +'"]').parent().removeClass("active")
22 | languageControls.find('a').filter('[data-language="' + language +'"]').parent().addClass("active")
23 |
24 | $('#selected-language').text(language)
25 |
26 | var codeBlocks = $('pre.highlight')
27 | codeBlocks.not('[data-language="' + language +'"]').addClass("hide")
28 | codeBlocks.filter('[data-language="' + language +'"]').removeClass("hide")
29 | })
30 |
31 | function formEntries (form) {
32 | // Polyfill for new FormData(form).entries()
33 | var formData = new FormData(form)
34 | if (formData.entries !== undefined) {
35 | return formData.entries()
36 | }
37 |
38 | var entries = []
39 |
40 | for (var {name, type, value, files, checked, selectedOptions} of Array.from(form.elements)) {
41 | if (!name) {
42 | continue
43 | }
44 |
45 | if (type === 'file') {
46 | for (var file of files) {
47 | entries.push([name, file])
48 | }
49 | } else if (type === 'select-multiple' || type === 'select-one') {
50 | for (var elm of Array.from(selectedOptions)) {
51 | entries.push([name, elm.value])
52 | }
53 | } else if (type === 'checkbox') {
54 | if (checked) {
55 | entries.push([name, value])
56 | }
57 | } else {
58 | entries.push([name, value])
59 | }
60 | }
61 | return entries
62 | }
63 |
64 | // API Explorer
65 | $('form.api-interaction').submit(function(event) {
66 | event.preventDefault();
67 |
68 | const form = $(this).closest("form");
69 | const key = form.data("key");
70 | var params = {};
71 |
72 | const entries = formEntries(form.get()[0]);
73 | for (var [paramKey, paramValue] of entries) {
74 | var elem = form.find("[name=" + paramKey + "]")
75 | var dataType = elem.data('type') || 'string'
76 |
77 | if (dataType === 'integer' && paramValue) {
78 | var value = parseInt(paramValue)
79 | if (!isNaN(value)) {
80 | params[paramKey] = value
81 | }
82 | } else if (dataType === 'number' && paramValue) {
83 | var value = parseFloat(paramValue)
84 | if (!isNaN(value)) {
85 | params[paramKey] = value
86 | }
87 | } else if (dataType === 'boolean' && paramValue) {
88 | var value = {
89 | 'true': true,
90 | 'false': false
91 | }[paramValue.toLowerCase()]
92 | if (value !== undefined) {
93 | params[paramKey]
94 | }
95 | } else if (dataType === 'array' && paramValue) {
96 | try {
97 | params[paramKey] = JSON.parse(paramValue)
98 | } catch (err) {
99 | // Ignore malformed JSON
100 | }
101 | } else if (dataType === 'object' && paramValue) {
102 | try {
103 | params[paramKey] = JSON.parse(paramValue)
104 | } catch (err) {
105 | // Ignore malformed JSON
106 | }
107 | } else if (dataType === 'string' && paramValue) {
108 | params[paramKey] = paramValue
109 | }
110 | }
111 |
112 | form.find(":checkbox").each(function( index ) {
113 | // Handle unselected checkboxes
114 | var name = $(this).attr("name");
115 | if (!params.hasOwnProperty(name)) {
116 | params[name] = false
117 | }
118 | })
119 |
120 | function requestCallback(request) {
121 | // Fill in the "GET /foo/" display.
122 | var parser = document.createElement('a');
123 | parser.href = request.url;
124 | const method = request.options.method
125 | const path = parser.pathname + parser.hash + parser.search
126 |
127 | form.find(".request-method").text(method)
128 | form.find(".request-url").text(path)
129 | }
130 |
131 | function responseCallback(response, responseText) {
132 | // Display the 'Data'/'Raw' control.
133 | form.closest(".modal-content").find(".toggle-view").removeClass("hide")
134 |
135 | // Fill in the "200 OK" display.
136 | form.find(".response-status-code").removeClass("label-success").removeClass("label-danger")
137 | if (response.ok) {
138 | form.find(".response-status-code").addClass("label-success")
139 | } else {
140 | form.find(".response-status-code").addClass("label-danger")
141 | }
142 | form.find(".response-status-code").text(response.status)
143 | form.find(".meta").removeClass("hide")
144 |
145 | // Fill in the Raw HTTP response display.
146 | var panelText = 'HTTP/1.1 ' + response.status + ' ' + response.statusText + '\n';
147 | response.headers.forEach(function(header, key) {
148 | panelText += normalizeHTTPHeader(key) + ': ' + header + '\n'
149 | })
150 | if (responseText) {
151 | panelText += '\n' + responseText
152 | }
153 | form.find(".response-raw-response").text(panelText)
154 | }
155 |
156 | // Instantiate a client to make the outgoing request.
157 | var options = {
158 | requestCallback: requestCallback,
159 | responseCallback: responseCallback,
160 | }
161 |
162 | // Setup authentication options.
163 | if (window.auth && window.auth.type === 'token') {
164 | // Header authentication
165 | options.auth = new coreapi.auth.TokenAuthentication({
166 | prefix: window.auth.scheme,
167 | token: window.auth.token
168 | })
169 | } else if (window.auth && window.auth.type === 'basic') {
170 | // Basic authentication
171 | options.auth = new coreapi.auth.BasicAuthentication({
172 | username: window.auth.username,
173 | password: window.auth.password
174 | })
175 | } else if (window.auth && window.auth.type === 'session') {
176 | // Session authentication
177 | options.auth = new coreapi.auth.SessionAuthentication({
178 | csrfCookieName: 'csrftoken',
179 | csrfHeaderName: 'X-CSRFToken'
180 | })
181 | }
182 |
183 | const client = new coreapi.Client(options)
184 |
185 | client.action(schema, key, params).then(function (data) {
186 | var response = JSON.stringify(data, null, 2);
187 | form.find(".request-awaiting").addClass("hide")
188 | form.find(".response-raw").addClass("hide")
189 | form.find(".response-data").addClass("hide")
190 | form.find(".response-data").text('')
191 | form.find(".response-data").jsonView(response)
192 |
193 | if (responseDisplay === 'data') {
194 | form.find(".response-data").removeClass("hide")
195 | } else {
196 | form.find(".response-raw").removeClass("hide")
197 | }
198 | }).catch(function (error) {
199 | var response = JSON.stringify(error.content, null, 2);
200 | form.find(".request-awaiting").addClass("hide")
201 | form.find(".response-raw").addClass("hide")
202 | form.find(".response-data").addClass("hide")
203 | form.find(".response-data").text('')
204 | form.find(".response-data").jsonView(response)
205 |
206 | if (responseDisplay === 'data') {
207 | form.find(".response-data").removeClass("hide")
208 | } else {
209 | form.find(".response-raw").removeClass("hide")
210 | }
211 | })
212 | });
213 |
214 | // 'Data'/'Raw' control
215 | $('.toggle-view button').click(function() {
216 | responseDisplay = $(this).data("display-toggle");
217 | $(this).removeClass("btn-default").addClass('btn-info').siblings().removeClass('btn-info');
218 | if (responseDisplay === 'raw') {
219 | $(this).closest(".modal-content").find(".response-raw").removeClass("hide");
220 | $(this).closest(".modal-content").find(".response-data").addClass("hide");
221 | } else {
222 | $(this).closest(".modal-content").find(".response-data").removeClass("hide");
223 | $(this).closest(".modal-content").find(".response-raw").addClass("hide");
224 | }
225 | });
226 |
227 | // Authentication: none
228 | $('#auth-control').find("[data-auth='none']").click(function (event) {
229 | event.preventDefault();
230 | window.auth = null;
231 | $('#selected-authentication').text('none');
232 | $('#auth-control').children().removeClass('active');
233 | $('#auth-control').find("[data-auth='none']").addClass('active');
234 | })
235 |
236 | // Authentication: token
237 | $('form.authentication-token-form').submit(function(event) {
238 | event.preventDefault();
239 | const form = $(this).closest("form");
240 | const scheme = form.find('input#scheme').val();
241 | const token = form.find('input#token').val();
242 | window.auth = {
243 | 'type': 'token',
244 | 'scheme': scheme,
245 | 'token': token
246 | };
247 | $('#selected-authentication').text('token');
248 | $('#auth-control').children().removeClass('active');
249 | $('#auth-control').find("[data-auth='token']").addClass('active');
250 | $('#auth_token_modal').modal('hide');
251 | });
252 |
253 | // Authentication: basic
254 | $('form.authentication-basic-form').submit(function(event) {
255 | event.preventDefault();
256 | const form = $(this).closest("form");
257 | const username = form.find('input#username').val();
258 | const password = form.find('input#password').val();
259 | window.auth = {
260 | 'type': 'basic',
261 | 'username': username,
262 | 'password': password
263 | };
264 | $('#selected-authentication').text('basic');
265 | $('#auth-control').children().removeClass('active');
266 | $('#auth-control').find("[data-auth='basic']").addClass('active');
267 | $('#auth_basic_modal').modal('hide');
268 | });
269 |
270 | // Authentication: session
271 | $('form.authentication-session-form').submit(function(event) {
272 | event.preventDefault();
273 | window.auth = {
274 | 'type': 'session',
275 | };
276 | $('#selected-authentication').text('session');
277 | $('#auth-control').children().removeClass('active');
278 | $('#auth-control').find("[data-auth='session']").addClass('active');
279 | $('#auth_session_modal').modal('hide');
280 | });
281 |
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/js/base.js:
--------------------------------------------------------------------------------
1 | function getSearchTerm()
2 | {
3 | var sPageURL = window.location.search.substring(1);
4 | var sURLVariables = sPageURL.split('&');
5 | for (var i = 0; i < sURLVariables.length; i++)
6 | {
7 | var sParameterName = sURLVariables[i].split('=');
8 | if (sParameterName[0] == 'q')
9 | {
10 | return sParameterName[1];
11 | }
12 | }
13 | }
14 |
15 | $(document).ready(function() {
16 |
17 | var search_term = getSearchTerm(),
18 | $search_modal = $('#mkdocs_search_modal');
19 |
20 | if(search_term){
21 | $search_modal.modal();
22 | }
23 |
24 | // make sure search input gets autofocus everytime modal opens.
25 | $search_modal.on('shown.bs.modal', function () {
26 | $search_modal.find('#mkdocs-search-query').focus();
27 | });
28 |
29 | // Highlight.js
30 | hljs.initHighlightingOnLoad();
31 | $('table').addClass('table table-striped table-hover');
32 | });
33 |
34 |
35 | $('body').scrollspy({
36 | target: '.bs-sidebar',
37 | });
38 |
39 | /* Prevent disabled links from causing a page reload */
40 | $("li.disabled a").click(function() {
41 | event.preventDefault();
42 | });
43 |
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/docs/js/jquery.json-view.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jquery.json-view - jQuery collapsible JSON plugin
3 | * @version v1.0.0
4 | * @link http://github.com/bazh/jquery.json-view
5 | * @license MIT
6 | */
7 | !function(e){"use strict";var n=function(n){var a=e("",{"class":"collapser",on:{click:function(){var n=e(this);n.toggleClass("collapsed");var a=n.parent().children(".block"),p=a.children("ul");n.hasClass("collapsed")?(p.hide(),a.children(".dots, .comments").show()):(p.show(),a.children(".dots, .comments").hide())}}});return n&&a.addClass("collapsed"),a},a=function(a,p){var t=e.extend({},{nl2br:!0},p),r=function(e){return e.toString()?e.toString().replace(/&/g,"&").replace(/"/g,""").replace(//g,">"):""},s=function(n,a){return e("",{"class":a,html:r(n)})},l=function(a,p){switch(e.type(a)){case"object":p||(p=0);var c=e("",{"class":"block"}),d=Object.keys(a).length;if(!d)return c.append(s("{","b")).append(" ").append(s("}","b"));c.append(s("{","b"));var i=e("
",{"class":"obj collapsible level"+p});return e.each(a,function(a,t){d--;var r=e("").append(s('"',"q")).append(a).append(s('"',"q")).append(": ").append(l(t,p+1));-1===["object","array"].indexOf(e.type(t))||e.isEmptyObject(t)||r.prepend(n()),d>0&&r.append(","),i.append(r)}),c.append(i),c.append(s("...","dots")),c.append(s("}","b")),c.append(1===Object.keys(a).length?s("// 1 item","comments"):s("// "+Object.keys(a).length+" items","comments")),c;case"array":p||(p=0);var d=a.length,c=e("",{"class":"block"});if(!d)return c.append(s("[","b")).append(" ").append(s("]","b"));c.append(s("[","b"));var i=e("
",{"class":"obj collapsible level"+p});return e.each(a,function(a,t){d--;var r=e("").append(l(t,p+1));-1===["object","array"].indexOf(e.type(t))||e.isEmptyObject(t)||r.prepend(n()),d>0&&r.append(","),i.append(r)}),c.append(i),c.append(s("...","dots")),c.append(s("]","b")),c.append(1===a.length?s("// 1 item","comments"):s("// "+a.length+" items","comments")),c;case"string":if(a=r(a),/^(http|https|file):\/\/[^\s]+$/i.test(a))return e("").append(s('"',"q")).append(e("",{href:a,text:a})).append(s('"',"q"));if(t.nl2br){var o=/\n/g;o.test(a)&&(a=(a+"").replace(o,"
"))}var u=e("",{"class":"str"}).html(a);return e("").append(s('"',"q")).append(u).append(s('"',"q"));case"number":return s(a.toString(),"num");case"undefined":return s("undefined","undef");case"null":return s("null","null");case"boolean":return s(a?"true":"false","bool")}};return l(a)};return e.fn.jsonView=function(n,p){var t=e(this);if(p=e.extend({},{nl2br:!0},p),"string"==typeof n)try{n=JSON.parse(n)}catch(r){}return t.append(e("",{"class":"json-view"}).append(a(n,p))),t}}(jQuery);
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/img/grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/payatu/Tiredful-API/0134124496b3c4f1b969e51a24fd8a059104fb98/Tiredful-API/static/rest_framework/img/grid.png
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/js/ajax-form.js:
--------------------------------------------------------------------------------
1 | function replaceDocument(docString) {
2 | var doc = document.open("text/html");
3 |
4 | doc.write(docString);
5 | doc.close();
6 | }
7 |
8 | function doAjaxSubmit(e) {
9 | var form = $(this);
10 | var btn = $(this.clk);
11 | var method = (
12 | btn.data('method') ||
13 | form.data('method') ||
14 | form.attr('method') || 'GET'
15 | ).toUpperCase();
16 |
17 | if (method === 'GET') {
18 | // GET requests can always use standard form submits.
19 | return;
20 | }
21 |
22 | var contentType =
23 | form.find('input[data-override="content-type"]').val() ||
24 | form.find('select[data-override="content-type"] option:selected').text();
25 |
26 | if (method === 'POST' && !contentType) {
27 | // POST requests can use standard form submits, unless we have
28 | // overridden the content type.
29 | return;
30 | }
31 |
32 | // At this point we need to make an AJAX form submission.
33 | e.preventDefault();
34 |
35 | var url = form.attr('action');
36 | var data;
37 |
38 | if (contentType) {
39 | data = form.find('[data-override="content"]').val() || ''
40 | } else {
41 | contentType = form.attr('enctype') || form.attr('encoding')
42 |
43 | if (contentType === 'multipart/form-data') {
44 | if (!window.FormData) {
45 | alert('Your browser does not support AJAX multipart form submissions');
46 | return;
47 | }
48 |
49 | // Use the FormData API and allow the content type to be set automatically,
50 | // so it includes the boundary string.
51 | // See https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects
52 | contentType = false;
53 | data = new FormData(form[0]);
54 | } else {
55 | contentType = 'application/x-www-form-urlencoded; charset=UTF-8'
56 | data = form.serialize();
57 | }
58 | }
59 |
60 | var ret = $.ajax({
61 | url: url,
62 | method: method,
63 | data: data,
64 | contentType: contentType,
65 | processData: false,
66 | headers: {
67 | 'Accept': 'text/html; q=1.0, */*'
68 | },
69 | });
70 |
71 | ret.always(function(data, textStatus, jqXHR) {
72 | if (textStatus != 'success') {
73 | jqXHR = data;
74 | }
75 |
76 | var responseContentType = jqXHR.getResponseHeader("content-type") || "";
77 |
78 | if (responseContentType.toLowerCase().indexOf('text/html') === 0) {
79 | replaceDocument(jqXHR.responseText);
80 |
81 | try {
82 | // Modify the location and scroll to top, as if after page load.
83 | history.replaceState({}, '', url);
84 | scroll(0, 0);
85 | } catch (err) {
86 | // History API not supported, so redirect.
87 | window.location = url;
88 | }
89 | } else {
90 | // Not HTML content. We can't open this directly, so redirect.
91 | window.location = url;
92 | }
93 | });
94 |
95 | return ret;
96 | }
97 |
98 | function captureSubmittingElement(e) {
99 | var target = e.target;
100 | var form = this;
101 |
102 | form.clk = target;
103 | }
104 |
105 | $.fn.ajaxForm = function() {
106 | var options = {}
107 |
108 | return this
109 | .unbind('submit.form-plugin click.form-plugin')
110 | .bind('submit.form-plugin', options, doAjaxSubmit)
111 | .bind('click.form-plugin', options, captureSubmittingElement);
112 | };
113 |
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/js/csrf.js:
--------------------------------------------------------------------------------
1 | function getCookie(name) {
2 | var cookieValue = null;
3 |
4 | if (document.cookie && document.cookie != '') {
5 | var cookies = document.cookie.split(';');
6 |
7 | for (var i = 0; i < cookies.length; i++) {
8 | var cookie = jQuery.trim(cookies[i]);
9 |
10 | // Does this cookie string begin with the name we want?
11 | if (cookie.substring(0, name.length + 1) == (name + '=')) {
12 | cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
13 | break;
14 | }
15 | }
16 | }
17 |
18 | return cookieValue;
19 | }
20 |
21 | function csrfSafeMethod(method) {
22 | // these HTTP methods do not require CSRF protection
23 | return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
24 | }
25 |
26 | function sameOrigin(url) {
27 | // test that a given url is a same-origin URL
28 | // url could be relative or scheme relative or absolute
29 | var host = document.location.host; // host + port
30 | var protocol = document.location.protocol;
31 | var sr_origin = '//' + host;
32 | var origin = protocol + sr_origin;
33 |
34 | // Allow absolute or scheme relative URLs to same origin
35 | return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
36 | (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
37 | // or any other URL that isn't scheme relative or absolute i.e relative.
38 | !(/^(\/\/|http:|https:).*/.test(url));
39 | }
40 |
41 | var csrftoken = getCookie(window.drf.csrfCookieName);
42 |
43 | $.ajaxSetup({
44 | beforeSend: function(xhr, settings) {
45 | if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
46 | // Send the token to same-origin, relative URLs only.
47 | // Send the token only if the method warrants CSRF protection
48 | // Using the CSRFToken value acquired earlier
49 | xhr.setRequestHeader(window.drf.csrfHeaderName, csrftoken);
50 | }
51 | }
52 | });
53 |
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/js/default.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function() {
2 | // JSON highlighting.
3 | prettyPrint();
4 |
5 | // Bootstrap tooltips.
6 | $('.js-tooltip').tooltip({
7 | delay: 1000,
8 | container: 'body'
9 | });
10 |
11 | // Deal with rounded tab styling after tab clicks.
12 | $('a[data-toggle="tab"]:first').on('shown', function(e) {
13 | $(e.target).parents('.tabbable').addClass('first-tab-active');
14 | });
15 |
16 | $('a[data-toggle="tab"]:not(:first)').on('shown', function(e) {
17 | $(e.target).parents('.tabbable').removeClass('first-tab-active');
18 | });
19 |
20 | $('a[data-toggle="tab"]').click(function() {
21 | document.cookie = "tabstyle=" + this.name + "; path=/";
22 | });
23 |
24 | // Store tab preference in cookies & display appropriate tab on load.
25 | var selectedTab = null;
26 | var selectedTabName = getCookie('tabstyle');
27 |
28 | if (selectedTabName) {
29 | selectedTabName = selectedTabName.replace(/[^a-z-]/g, '');
30 | }
31 |
32 | if (selectedTabName) {
33 | selectedTab = $('.form-switcher a[name=' + selectedTabName + ']');
34 | }
35 |
36 | if (selectedTab && selectedTab.length > 0) {
37 | // Display whichever tab is selected.
38 | selectedTab.tab('show');
39 | } else {
40 | // If no tab selected, display rightmost tab.
41 | $('.form-switcher a:first').tab('show');
42 | }
43 |
44 | $(window).load(function() {
45 | $('#errorModal').modal('show');
46 | });
47 | });
48 |
--------------------------------------------------------------------------------
/Tiredful-API/static/rest_framework/js/prettify-min.js:
--------------------------------------------------------------------------------
1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]+/],["dec",/^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^
14 |
15 |
16 |
24 |
--------------------------------------------------------------------------------
/Tiredful-API/templates/elements/navbar.html:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
32 |
--------------------------------------------------------------------------------
/Tiredful-API/templates/elements/sidebar.html:
--------------------------------------------------------------------------------
1 |
11 |
12 |
23 |
--------------------------------------------------------------------------------
/Tiredful-API/templates/scenario-basic.html:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | {% block title-text %} {% endblock %}
21 |
22 | {# including css element #}
23 | {% include 'elements/css-content.html' %}
24 |
25 |
26 |
27 |
28 |
29 | {# including navbar element #}
30 | {% include 'elements/navbar.html' %}
31 |
32 |
33 |
34 |
39 | {% block content %}
40 | {% endblock %}
41 |
42 |
43 |
38 |
44 | {# including javascript element #}
45 | {% include 'elements/javascript-content.html' %}
46 |
47 | {# For page specific javascript #}
48 | {% block page-level-js %}
49 | {% endblock %}
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Tiredful-API/trains/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __
4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( )
5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )(
6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__)
7 | #
8 | #
9 | # Copyright (C) 2017-2018 Payatu Software Labs
10 | # This file is part of Tiredful API application
11 |
--------------------------------------------------------------------------------
/Tiredful-API/trains/apps.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __
4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( )
5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )(
6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__)
7 | #
8 | #
9 | # Copyright (C) 2017-2018 Payatu Software Labs
10 | # This file is part of Tiredful API application
11 |
12 | from __future__ import unicode_literals
13 |
14 | from django.apps import AppConfig
15 |
16 |
17 | class TrainsConfig(AppConfig):
18 | name = 'trains'
19 |
--------------------------------------------------------------------------------
/Tiredful-API/trains/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __
4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( )
5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )(
6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__)
7 | #
8 | #
9 | # Copyright (C) 2017-2018 Payatu Software Labs
10 | # This file is part of Tiredful API application
11 |
12 | from __future__ import unicode_literals
13 |
14 | from django.db import models
15 |
16 | WAITING = 'W'
17 | CONFIRM = 'CNF'
18 | RAC = 'RAC'
19 | STATUS_CHOICES = (
20 | (WAITING, 'Waiting'),
21 | (CONFIRM, 'Confirm'),
22 | (RAC, 'RAC'),
23 | )
24 |
25 |
26 | class Reservation(models.Model):
27 | train_number = models.IntegerField()
28 | PNR = models.CharField(max_length=40)
29 | status = models.CharField(
30 | max_length=3,
31 | choices=STATUS_CHOICES,
32 | default=CONFIRM,
33 | )
34 |
--------------------------------------------------------------------------------
/Tiredful-API/trains/serializers.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __
4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( )
5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )(
6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__)
7 | #
8 | #
9 | # Copyright (C) 2017-2018 Payatu Software Labs
10 | # This file is part of Tiredful API application
11 |
12 | from rest_framework import serializers
13 |
14 | from trains.models import Reservation
15 | from django.contrib.auth.models import User
16 |
17 |
18 | # ScoreCard object serializer
19 | class ReservationSerializers(serializers.ModelSerializer):
20 | class Meta:
21 | model = Reservation
22 | fields = ('train_number', 'PNR', 'status')
23 |
--------------------------------------------------------------------------------
/Tiredful-API/trains/templates/trains/index.html:
--------------------------------------------------------------------------------
1 |
11 | {% extends 'scenario-basic.html' %}
12 |
13 | {% block title-text %} Tiredful API: Rate Limit Implementation {% endblock %}
14 |
15 | {% block content %}
16 | Challenge: Rate Limit Implementation
17 |
18 | This challenge is to show the missing rate limit implementation issue.
19 | Missing rate limit implementation allow attacker to abuse system resources by launching a DOS attack.
20 |
21 |
22 | Following is the API end point:
23 | POST http://{{ request.get_host }}/api/v1/trains/
24 |
25 |
26 | POST:
27 |
28 | {
29 | "PNR": <pnr_number(string)>
30 | }
31 |
32 |
33 |
34 |
35 | Following are the train PNR numbers available:
36 | {# Message notifications #}
37 | {% if pnr_numbers %}
38 |
39 | {% for pnr in pnr_numbers %}
40 | - {{ pnr }}
41 | {% endfor %}
42 |
43 | {% endif %}
44 |
45 | Aim: Force server to respond with HTTP response code 429.
46 | {% endblock %}
47 |
--------------------------------------------------------------------------------
/Tiredful-API/trains/urls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __
4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( )
5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )(
6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__)
7 | #
8 | #
9 | # Copyright (C) 2017-2018 Payatu Software Labs
10 | # This file is part of Tiredful API application
11 |
12 | from django.conf.urls import url
13 | from . import views
14 |
15 | urlpatterns = [
16 |
17 | # ex: /trains/
18 | url(r'^$', views.index, name='index'),
19 |
20 | # ex: /trains/
21 | url(r'^trains/$', views.get_status, name='trains'),
22 |
23 | ]
24 |
--------------------------------------------------------------------------------
/Tiredful-API/trains/views.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # ____ __ ___ ___ ___ ___ _ _ __ __ ___ __
4 | # (_ _)( )( ,) ( _)( \( _)( )( )( ) ( ) ( ,\( )
5 | # )( )( ) \ ) _) ) ) )) _) )()( )(__ /__\ ) _/ )(
6 | # (__) (__)(_)\_)(___)(___/(_) \__/ (____) (_)(_)(_) (__)
7 | #
8 | #
9 | # Copyright (C) 2017-2018 Payatu Software Labs
10 | # This file is part of Tiredful API application
11 |
12 | from __future__ import unicode_literals
13 |
14 | from django.shortcuts import render
15 | from django.views.decorators.csrf import csrf_exempt
16 | from trains.models import Reservation
17 | from trains.serializers import ReservationSerializers
18 |
19 | from rest_framework import status
20 | from rest_framework.decorators import api_view, throttle_classes
21 | from rest_framework.response import Response
22 | from rest_framework.throttling import UserRateThrottle
23 |
24 |
25 | # Index page for rate limit challenge
26 | def index(request):
27 | """
28 | Method for challenge description
29 | """
30 | pnr_numbers = Reservation.objects.values_list('PNR', flat=True)
31 | return render(request, 'trains/index.html', {'pnr_numbers': pnr_numbers})
32 |
33 |
34 | # API view to get information of reservation status
35 | @api_view(['POST'])
36 | @throttle_classes([UserRateThrottle])
37 | def get_status(request):
38 | """
39 | Get train status
40 | """
41 | if request.method == 'POST':
42 | if request.data:
43 | if 'PNR' in request.data.keys():
44 | pnr_requested = request.data['PNR']
45 | try:
46 | reservation_detail = Reservation.objects.get(PNR=pnr_requested)
47 | serializer = ReservationSerializers(reservation_detail)
48 | return Response(serializer.data)
49 | except Reservation.DoesNotExist:
50 | return Response(status=status.HTTP_404_NOT_FOUND)
51 | else:
52 | return Response(status=status.HTTP_400_BAD_REQUEST)
53 | else:
54 | return Response(status=status.HTTP_400_BAD_REQUEST)
55 | else:
56 | return Response(status=status.HTTP_400_BAD_REQUEST)
57 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Django==1.11.7
2 | django-oauth-toolkit==1.0.0
3 | djangorestframework==3.7.3
4 | oauth==1.0.1
5 | oauthlib==2.0.6
6 | python-oauth2==1.0.1
7 |
--------------------------------------------------------------------------------