├── assets └── clippy.swf ├── permgen.cpp ├── test.cpp ├── .github └── workflows │ └── test.yml ├── permgen.h ├── CMake ├── FindSqlite3.cmake ├── FindFCGIPP.cmake └── FindCppUnit.cmake ├── error.html ├── insults.txt ├── test_permgen.cpp ├── insults.h ├── README.md ├── index.html ├── database.h ├── created.html ├── CMakeLists.txt ├── Vagrantfile ├── test_insults.cpp ├── template.h ├── test_database.cpp ├── insults.cpp ├── test_template.cpp ├── template.cpp ├── database.cpp └── cgi.cpp /assets/clippy.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remram44/insurlt/HEAD/assets/clippy.swf -------------------------------------------------------------------------------- /permgen.cpp: -------------------------------------------------------------------------------- 1 | #include "permgen.h" 2 | 3 | 4 | constexpr Key M = 0xFFFFFFFF; 5 | constexpr Key A = 1103515245; 6 | constexpr Key C = 12345; 7 | 8 | Generator::Generator(Key max) 9 | : m_Max(max) 10 | { 11 | } 12 | 13 | Key Generator::generate(Key state) 14 | { 15 | do 16 | state = (A * state + C) & M; 17 | while(state > m_Max); 18 | return state; 19 | } 20 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | int main() 6 | { 7 | CppUnit::TextUi::TestRunner runner; 8 | CppUnit::TestFactoryRegistry ®istry = 9 | CppUnit::TestFactoryRegistry::getRegistry(); 10 | runner.addTest(registry.makeTest()); 11 | bool wasSuccessful = runner.run("", false); 12 | return !wasSuccessful; 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Install dependencies 13 | run: | 14 | sudo apt-get update -qq 15 | sudo apt-get install -qq libfcgi-dev libsqlite3-dev libcppunit-dev 16 | - name: Build 17 | run: | 18 | mkdir ../build 19 | cd ../build 20 | cmake ../insurlt -DBUILD_TESTS:BOOL=on 21 | make -j2 22 | - name: Run tests 23 | run: ../build/tests 24 | -------------------------------------------------------------------------------- /permgen.h: -------------------------------------------------------------------------------- 1 | #ifndef PERMGEN_H 2 | #define PERMGEN_H 3 | 4 | #include 5 | 6 | 7 | typedef std::uint_fast32_t Key; 8 | 9 | 10 | /** 11 | * Generates a random permutation on 32-bit integers. 12 | * 13 | * Warning: max should be set to a value close to 2^32. Generation will take 14 | * mean time proportional to 2^32/max 15 | */ 16 | class Generator { 17 | 18 | private: 19 | const Key m_Max; 20 | 21 | public: 22 | /** 23 | * Constructor. 24 | * 25 | * @param max Maximum number to return (inclusive). 26 | */ 27 | Generator(Key max); 28 | Key generate(Key previous); 29 | 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /CMake/FindSqlite3.cmake: -------------------------------------------------------------------------------- 1 | # Look for the header file. 2 | FIND_PATH(SQLITE3_INCLUDE_DIR NAMES sqlite3.h) 3 | 4 | # Look for the library. 5 | FIND_LIBRARY(SQLITE3_LIBRARY NAMES sqlite3) 6 | 7 | # Handle the QUIETLY and REQUIRED arguments and set Sqlite3_FOUND to TRUE if all listed variables are TRUE. 8 | INCLUDE(FindPackageHandleStandardArgs) 9 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Sqlite3 DEFAULT_MSG SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR) 10 | 11 | # Copy the results to the output variables. 12 | IF(SQLITE3_FOUND) 13 | SET(SQLITE3_LIBRARIES ${SQLITE3_LIBRARY}) 14 | SET(SQLITE3_INCLUDE_DIRS ${SQLITE3_INCLUDE_DIR}) 15 | ELSE(Sqlite3_FOUND) 16 | SET(SQLITE3_LIBRARIES) 17 | SET(SQLITE3_INCLUDE_DIRS) 18 | ENDIF(SQLITE3_FOUND) 19 | 20 | MARK_AS_ADVANCED(SQLITE3_INCLUDE_DIR SQLITE3_LIBRARY) 21 | -------------------------------------------------------------------------------- /CMake/FindFCGIPP.cmake: -------------------------------------------------------------------------------- 1 | # Look for the header file. 2 | FIND_PATH(FCGIPP_INCLUDE_DIR NAMES fastcgi.h) 3 | 4 | # Look for the library. 5 | FIND_LIBRARY(FCGI_LIBRARY NAMES fcgi) 6 | FIND_LIBRARY(FCGIPP_LIBRARY NAMES fcgi++) 7 | 8 | # Handle the QUIETLY and REQUIRED arguments and set FCGIPP_FOUND to TRUE if all listed variables are TRUE. 9 | INCLUDE(FindPackageHandleStandardArgs) 10 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(FCGIPP DEFAULT_MSG FCGI_LIBRARY FCGIPP_LIBRARY FCGIPP_INCLUDE_DIR) 11 | 12 | # Copy the results to the output variables. 13 | IF(FCGIPP_FOUND) 14 | SET(FCGIPP_LIBRARIES ${FCGI_LIBRARY} ${FCGIPP_LIBRARY}) 15 | SET(FCGIPP_INCLUDE_DIRS ${FCGIPP_INCLUDE_DIR}) 16 | ELSE(FCGIPP_FOUND) 17 | SET(FCGIPP_LIBRARIES) 18 | SET(FCGIPP_INCLUDE_DIRS) 19 | ENDIF(FCGIPP_FOUND) 20 | 21 | MARK_AS_ADVANCED(FCGIPP_INCLUDE_DIR FCGI_LIBRARY FCGIPP_LIBRARY) 22 | -------------------------------------------------------------------------------- /error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | La résurrection du rallongeur d'URL de Nicolas ANELKA 5 | 22 | 23 | 24 |
25 |

{{ message }}

26 |

Retourne à l'index, salope.

27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /insults.txt: -------------------------------------------------------------------------------- 1 | vas-y clique ou allez.clique-salope.com 2 | 3 | N: 4 | salope 5 | gros con 6 | pauvre con 7 | sale fils de pute 8 | petite bite 9 | fils de chienne 10 | grosse merde 11 | vieux chacal 12 | sale encule 13 | gros batard 14 | V: 15 | va trouer le cul de 16 | va gifler 17 | va defoncer l-anus de 18 | va tuer 19 | va crever 20 | va cracher sur 21 | O: 22 | ta fille 23 | ta grand mere 24 | ton grand pere 25 | ton chien 26 | ta femme 27 | ta chienne 28 | ta soeur 29 | ton frere 30 | L: 31 | au cimetiere 32 | chez le coiffeur 33 | dans ma cave 34 | dans la cave 35 | sous ma caisse 36 | dans les champs 37 | dans ton cul 38 | dans la niche 39 | a carrefour 40 | I: 41 | raclure de chiottes 42 | face de pet 43 | sous merde 44 | sale batard 45 | pauvre merde 46 | fils de chien 47 | grosse pute 48 | sale enflure 49 | petite catin 50 | 51 | Each space can be either . or -, total: 3609722880 possibilities 52 | -------------------------------------------------------------------------------- /test_permgen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "permgen.h" 4 | 5 | 6 | class PermGen_test : public CppUnit::TestFixture { 7 | 8 | public: 9 | void test_generate() 10 | { 11 | std::vector keys; 12 | { 13 | Generator gen(3456789012); 14 | Key state = 0; 15 | for(size_t i = 0; i < 10; ++i) 16 | { 17 | state = gen.generate(state); 18 | CPPUNIT_ASSERT(state <= 3456789012); 19 | keys.push_back(state); 20 | } 21 | } 22 | { 23 | Generator gen2(3456789012); 24 | Key state = keys[4]; 25 | for(size_t i = 0; i < 5; ++i) 26 | { 27 | state = gen2.generate(state); 28 | CPPUNIT_ASSERT(state == keys[5+i]); 29 | } 30 | } 31 | } 32 | 33 | CPPUNIT_TEST_SUITE(PermGen_test); 34 | CPPUNIT_TEST(test_generate); 35 | CPPUNIT_TEST_SUITE_END(); 36 | 37 | }; 38 | 39 | CPPUNIT_TEST_SUITE_REGISTRATION(PermGen_test); 40 | -------------------------------------------------------------------------------- /insults.h: -------------------------------------------------------------------------------- 1 | #ifndef INSULTS_H 2 | #define INSULTS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "permgen.h" 9 | 10 | 11 | class Chooser { 12 | 13 | private: 14 | std::vector m_Choices; 15 | 16 | private: 17 | void gen_choices(const std::string &orig, size_t index, 18 | const std::string &prefix); 19 | 20 | public: 21 | Chooser(std::initializer_list choices); 22 | const std::string &operator()(Key &key) const; 23 | size_t size() const; 24 | 25 | }; 26 | 27 | 28 | class CombinedChoosers { 29 | 30 | private: 31 | std::vector m_Choosers; 32 | 33 | public: 34 | CombinedChoosers(std::initializer_list choosers); 35 | std::string operator()(Key key) const; 36 | size_t size() const; 37 | 38 | }; 39 | 40 | 41 | class Insults { 42 | 43 | private: 44 | CombinedChoosers m_Choosers; 45 | 46 | public: 47 | static constexpr Key CHOICES = 3609722880; 48 | 49 | Insults(); 50 | std::string generate(Key state); 51 | 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # insurlt: An offensive URL-lengthener service 2 | 3 | [![Build Status](https://github.com/remram44/insurlt/workflows/Test/badge.svg)](https://github.com/remram44/insurlt/actions) [![Say Thanks!](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/remram44) 4 | 5 | # Introduction 6 | 7 | This is a webapp that creates redirects to user-supplied URLs, the same way the 8 | more common URL-shortener services do (bit.ly, goo.gl, t.co). Except it makes 9 | them very long, and full of obscenities. 10 | 11 | It is written in C++, the obvious tool for the job. 12 | 13 | This service used to exist as clique-salope.com, however it looks like it has 14 | now been discontinued. Being such an important piece of the modern Internet, 15 | someone had to put it back online. 16 | 17 | # How to setup 18 | 19 | You will need CMake, SQLite3, the fastcgi development kit, and a C++11 20 | compiler like GCC >=4.6 or Clang >=2.9. 21 | 22 | Simply configure your web server to point to the insurlt.fcgi binary. You will 23 | need to update the source to match your domain name and favorite insults. 24 | 25 | # Check it out 26 | 27 | http://clique-salope.ovh/ (original French version) 28 | http://click-bitch.ovh/ (English translation) 29 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | La résurrection du rallongeur d'URL de Nicolas ANELKA 5 | 25 | 26 | 27 |
28 |

Le rallongeur d'URL de la résurrection de Nicolas ANELKA

29 |

Le rallongeur de résurrection d'URL de Nicolas ANELKA

30 |

L'URL de la résurrection du rallongeur de Nicolas ANELKA

31 |

Oh, ta gueule et clique, salope.

32 |
33 | 34 | 35 |
36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /database.h: -------------------------------------------------------------------------------- 1 | #ifndef DATABASE_H 2 | #define DATABASE_H 3 | 4 | #include 5 | #include 6 | 7 | #include "permgen.h" 8 | 9 | 10 | class DatabaseError : std::exception { 11 | 12 | private: 13 | const std::string m_Message; 14 | 15 | public: 16 | DatabaseError(const std::string &msg); 17 | ~DatabaseError() throw(); 18 | const char *what() const throw(); 19 | 20 | }; 21 | 22 | 23 | /** 24 | * The Database stores the URLs and the state of the generator. 25 | */ 26 | class Database { 27 | 28 | private: 29 | Generator &m_Generator; 30 | 31 | sqlite3 *m_DB; 32 | 33 | sqlite3_stmt *m_stmtGetState; 34 | sqlite3_stmt *m_stmtSetState; 35 | sqlite3_stmt *m_stmtInsertURL; 36 | sqlite3_stmt *m_stmtGetURL; 37 | sqlite3_stmt *m_stmtIncrementURLViews; 38 | sqlite3_stmt *m_stmtGetViews; 39 | sqlite3_stmt *m_stmtBegin; 40 | sqlite3_stmt *m_stmtCommit; 41 | sqlite3_stmt *m_stmtRollback; 42 | 43 | protected: 44 | void incrementViews(const std::string &our_url) throw(DatabaseError); 45 | 46 | public: 47 | Database(const char *filepath, Generator &generator) throw(DatabaseError); 48 | ~Database(); 49 | 50 | void storeURL(const std::string &our_url, 51 | const std::string &their_url, 52 | const std::string &their_address) throw(DatabaseError); 53 | std::string resolveURL(const std::string &our_url, 54 | bool increment_views) throw(DatabaseError); 55 | 56 | unsigned int getViews(const std::string &our_url) throw(DatabaseError); 57 | 58 | sqlite3_int64 getState() throw(DatabaseError); 59 | void setState(sqlite3_int64 state) throw(DatabaseError); 60 | Key nextState() throw(DatabaseError); 61 | 62 | }; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /created.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | La résurrection du rallongeur d'URL de Nicolas ANELKA 5 | 24 | 25 | 26 |
27 |

C'est long, hein.

28 | 29 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 50 | 51 |
52 | 53 | 54 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 2 | PROJECT(insurlt) 3 | 4 | IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR 5 | "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 6 | SET(CMAKE_CXX_FLAGS "-Wall -std=c++0x") 7 | ENDIF() 8 | 9 | SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH}) 10 | 11 | FIND_PACKAGE(FCGIPP REQUIRED) 12 | INCLUDE_DIRECTORIES(${FCGIPP_INCLUDE_DIRS}) 13 | SET(EXTRA_LIBRARIES ${FCGIPP_LIBRARIES} ${EXTRA_LIBRARIES}) 14 | 15 | FIND_PACKAGE(Sqlite3 REQUIRED) 16 | INCLUDE_DIRECTORIES(${SQLITE3_INCLUDE_DIRS}) 17 | SET(EXTRA_LIBRARIES ${SQLITE3_LIBRARIES} ${EXTRA_LIBRARIES}) 18 | 19 | # Makes public/ directory 20 | ADD_CUSTOM_TARGET( 21 | public 22 | COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/public") 23 | 24 | # Copies assets 25 | ADD_CUSTOM_TARGET( 26 | assets ALL 27 | COMMAND ${CMAKE_COMMAND} -E copy_if_different 28 | ${CMAKE_SOURCE_DIR}/assets/clippy.swf 29 | "${CMAKE_BINARY_DIR}/public/clippy.swf") 30 | 31 | # Build source list 32 | SET(INSURLT_FILES permgen.cpp insults.cpp database.cpp template.cpp) 33 | 34 | # Build executable 35 | ADD_EXECUTABLE(insurlt cgi.cpp ${INSURLT_FILES}) 36 | TARGET_LINK_LIBRARIES(insurlt ${EXTRA_LIBRARIES}) 37 | SET_TARGET_PROPERTIES( 38 | insurlt PROPERTIES 39 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/public" 40 | OUTPUT_NAME "insurlt.fcgi") 41 | ADD_DEPENDENCIES(insurlt public) 42 | 43 | # Test binary 44 | OPTION(BUILD_TESTS "Build the tests program" OFF) 45 | IF(BUILD_TESTS) 46 | FIND_PACKAGE(CppUnit REQUIRED) 47 | INCLUDE_DIRECTORIES(${CPPUNIT_INCLUDE_DIRS}) 48 | 49 | SET(TESTS_FILES test.cpp 50 | test_permgen.cpp test_insults.cpp test_database.cpp test_template.cpp 51 | ${INSURLT_FILES}) 52 | 53 | ADD_EXECUTABLE(tests ${TESTS_FILES}) 54 | TARGET_LINK_LIBRARIES(tests ${EXTRA_LIBRARIES} ${CPPUNIT_LIBRARIES}) 55 | ENDIF() 56 | -------------------------------------------------------------------------------- /CMake/FindCppUnit.cmake: -------------------------------------------------------------------------------- 1 | # - Find CppUnit 2 | # Find the CppUnit libraries 3 | # 4 | # This module defines the following variables: 5 | # CPPUNIT_FOUND - True if CPPUNIT_INCLUDE_DIR & CPPUNIT_LIBRARY are found 6 | # CPPUNIT_LIBRARIES - Set when CPPUNIT_LIBRARY is found 7 | # CPPUNIT_INCLUDE_DIRS - Set when CPPUNIT_INCLUDE_DIR is found 8 | # 9 | # CPPUNIT_INCLUDE_DIR - where to find asoundlib.h, etc. 10 | # CPPUNIT_LIBRARY - the CppUnit library 11 | # 12 | 13 | #============================================================================= 14 | # Adapted from FindALSA.cmake by Remi Rampin, 2014. 15 | #============================================================================= 16 | # Copyright 2009-2011 Kitware, Inc. 17 | # Copyright 2009-2011 Philip Lowman 18 | # 19 | # Distributed under the OSI-approved BSD License (the "License"); 20 | # see accompanying file Copyright.txt for details. 21 | # 22 | # This software is distributed WITHOUT ANY WARRANTY; without even the 23 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 24 | # See the License for more information. 25 | #============================================================================= 26 | # (To distribute this file outside of CMake, substitute the full 27 | # License text for the above reference.) 28 | 29 | find_path(CPPUNIT_INCLUDE_DIR NAMES cppunit/ui/text/TestRunner.h 30 | DOC "The CppUnit include directory" 31 | ) 32 | 33 | find_library(CPPUNIT_LIBRARY NAMES cppunit 34 | DOC "The CppUnit library" 35 | ) 36 | 37 | # handle the QUIETLY and REQUIRED arguments and set CPPUNIT_FOUND to TRUE if 38 | # all listed variables are TRUE 39 | include(FindPackageHandleStandardArgs) 40 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(CppUnit 41 | REQUIRED_VARS CPPUNIT_LIBRARY CPPUNIT_INCLUDE_DIR) 42 | 43 | if(CPPUNIT_FOUND) 44 | set( CPPUNIT_LIBRARIES ${CPPUNIT_LIBRARY} ) 45 | set( CPPUNIT_INCLUDE_DIRS ${CPPUNIT_INCLUDE_DIR} ) 46 | endif() 47 | 48 | mark_as_advanced(CPPUNIT_INCLUDE_DIR CPPUNIT_LIBRARY) 49 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | VAGRANTFILE_API_VERSION = "2" 5 | 6 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 7 | config.vm.box = "remram/debian-7-amd64" 8 | 9 | config.vm.provision "shell", 10 | inline: <