├── .dockerignore ├── .github ├── .gitkeep └── workflows │ ├── build.yml │ └── docker-image.yml ├── .gitignore ├── .root ├── Dockerfile ├── LICENSE ├── README.md ├── keys ├── private.key └── public.key ├── lang ├── README_FR.md └── README_RU.md ├── lib ├── license.rb └── license │ ├── boundary.rb │ ├── encryptor.rb │ └── version.rb ├── make.sh └── src ├── generator.keys.rb ├── generator.license.rb ├── modify.license.rb └── scan.features.rb /.dockerignore: -------------------------------------------------------------------------------- 1 | langs/ 2 | README.md 3 | LICENSE 4 | .github/ 5 | Dockerfile 6 | .*ignore 7 | -------------------------------------------------------------------------------- /.github/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CucumberTomato/GitLab-License-Generator/4e8dbfe60a72880d3533bf6ee845e7b06e5f7472/.github/.gitkeep -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Ruby Gem 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [ "main" ] 7 | pull_request: 8 | branches: [ "main" ] 9 | schedule: 10 | - cron: "0 1 * * *" 11 | 12 | jobs: 13 | rebuild: 14 | runs-on: macos-latest 15 | steps: 16 | - name: Checkout Source Code 17 | uses: actions/checkout@v4 18 | - name: Build 19 | run: | 20 | ./make.sh 21 | - name: Upload Artifacts 22 | uses: actions/upload-artifact@v4 23 | with: 24 | name: build 25 | path: build 26 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # GitHub recommends pinning actions to a commit SHA. 7 | # To get a newer version, you will need to update the SHA. 8 | # You can also reference a tag or branch, but the action may change without warning. 9 | 10 | name: Publish Container to Github at dev 11 | 12 | on: 13 | push: 14 | branches: 15 | - 'main' 16 | 17 | env: 18 | REGISTRY: ghcr.io 19 | IMAGE_NAME: ${{ github.repository }} 20 | 21 | jobs: 22 | build-and-push-image: 23 | runs-on: ubuntu-latest 24 | permissions: 25 | contents: read 26 | packages: write 27 | steps: 28 | - name: Checkout repository 29 | uses: actions/checkout@v3 30 | - name: Log in to the Container registry 31 | uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 32 | with: 33 | registry: ${{ env.REGISTRY }} 34 | username: ${{ github.actor }} 35 | password: ${{ secrets.GITHUB_TOKEN }} 36 | - name: Extract metadata (tags, labels) for Docker 37 | id: meta 38 | uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 39 | with: 40 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 41 | - name: Build and push Docker image 42 | uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 43 | with: 44 | context: . 45 | push: true 46 | tags: ${{ steps.meta.outputs.tags }} 47 | labels: ${{ steps.meta.outputs.labels }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /spec/examples.txt 9 | /test/tmp/ 10 | /test/version_tmp/ 11 | /tmp/ 12 | 13 | # Used by dotenv library to load environment variables. 14 | # .env 15 | 16 | # Ignore Byebug command history file. 17 | .byebug_history 18 | 19 | ## Specific to RubyMotion: 20 | .dat* 21 | .repl_history 22 | build/ 23 | *.bridgesupport 24 | build-iPhoneOS/ 25 | build-iPhoneSimulator/ 26 | 27 | ## Specific to RubyMotion (use of CocoaPods): 28 | # 29 | # We recommend against adding the Pods directory to your .gitignore. However 30 | # you should judge for yourself, the pros and cons are mentioned at: 31 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 32 | # 33 | # vendor/Pods/ 34 | 35 | ## Documentation cache and generated files: 36 | /.yardoc/ 37 | /_yardoc/ 38 | /doc/ 39 | /rdoc/ 40 | 41 | ## Environment normalization: 42 | /.bundle/ 43 | /vendor/bundle 44 | /lib/bundler/man/ 45 | 46 | # for a library or gem, you might want to ignore these files since the code is 47 | # intended to run in multiple environments; otherwise, check them in: 48 | # Gemfile.lock 49 | # .ruby-version 50 | # .ruby-gemset 51 | 52 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 53 | .rvmrc 54 | 55 | # Used by RuboCop. Remote config files pulled in from inherit_from directive. 56 | # .rubocop-https?--* 57 | 58 | temp/ 59 | output/ 60 | license_key 61 | license_key.pub 62 | result.gitlab-license 63 | features.list 64 | .DS_Store 65 | -------------------------------------------------------------------------------- /.root: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CucumberTomato/GitLab-License-Generator/4e8dbfe60a72880d3533bf6ee845e7b06e5f7472/.root -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:bookworm 2 | WORKDIR /license-generator 3 | COPY ./ ./ 4 | RUN < 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # GitLab License Generator 4 | 5 |

6 | English | 7 | Français | 8 | Russian 9 |

10 | 11 |
12 | 13 | ## Description 14 | 15 | **GitLab License Generator** This project generates a GitLab license for **development purposes**. If you encounter any problems, please troubleshoot them on your own. 16 | 17 | > Last tested on GitLab v17.6.0-ee. 18 | 19 | ## Principles 20 | 21 | ### **src/generator.keys.rb** 22 | 23 | GitLab uses a public/private key pair to encrypt its license. The public key is shipped with the GitLab distribution, while the private key is kept secure. The license itself is simply a JSON dictionary. Since GitLab has made its code open-source, we can easily generate our own license. 24 | 25 | ### **src/generator.license.rb** 26 | 27 | The `lib` folder is extracted from GitLab's source code. It is used to build and validate the license. The script `src/generator.license.rb` loads this functionality. 28 | 29 | ### **src/scan.features.rb** 30 | 31 | Removed with a script to generate empty json file due to DMCA takedown request. 32 | 33 | ~~Features are extracted from an object filled with constants. The most comprehensive plan for a license is **Ultimate**, but features like Geo Mirroring are not included in any standard plan. Therefore, we manually add these features.~~ 34 | 35 | ## Usage 36 | 37 | ### Using Docker image (Zero setup) 38 | 39 | Using this method license files are generated under `./license` directory 40 | > Please note that in standard docker installations, owner of the files generated in license directory will be root 41 | 42 | #### Method (1): Pull image 43 | 44 | ```bash 45 | docker run --rm -it \ 46 | -v "./license:/license-generator/build" \ 47 | -e LICENSE_NAME="Tim Cook" \ 48 | -e LICENSE_COMPANY="Apple Computer, Inc." \ 49 | -e LICENSE_EMAIL="tcook@apple.com" \ 50 | -e LICENSE_PLAN="ultimate" \ 51 | -e LICENSE_USER_COUNT="2147483647" \ 52 | -e LICENSE_EXPIRE_YEAR="2500" \ 53 | ghcr.io/lakr233/gitlab-license-generator:main 54 | ``` 55 | 56 | #### Method (2): Build image 57 | 58 | ```bash 59 | git clone https://github.com/Lakr233/GitLab-License-Generator.git 60 | docker build GitLab-License-Generator -t gitlab-license-generator:main 61 | docker run --rm -it \ 62 | -v "./license:/license-generator/build" \ 63 | -e LICENSE_NAME="Tim Cook" \ 64 | -e LICENSE_COMPANY="Apple Computer, Inc." \ 65 | -e LICENSE_EMAIL="tcook@apple.com" \ 66 | -e LICENSE_PLAN="ultimate" \ 67 | -e LICENSE_USER_COUNT="2147483647" \ 68 | -e LICENSE_EXPIRE_YEAR="2500" \ 69 | gitlab-license-generator:main 70 | ``` 71 | 72 | ### Manual: Prerequisites 73 | 74 | Before starting, ensure your environment is properly configured. 75 | 76 | #### 1. Install Ruby and gem 77 | 78 | To run this project, you need **Ruby** and the **gem** package manager. 79 | 80 | - **On Linux (Ubuntu/Debian)**: 81 | 82 | ```bash 83 | sudo apt update 84 | sudo apt install ruby-full 85 | ``` 86 | 87 | - **On macOS** (via Homebrew): 88 | 89 | ```bash 90 | brew install ruby 91 | ``` 92 | 93 | #### 2. Install Bundler and necessary gems 94 | 95 | After installing Ruby, you need to install **Bundler** to manage Ruby dependencies. 96 | 97 | ```bash 98 | gem install bundler 99 | ``` 100 | 101 | #### 3. Install the `gitlab-license` gem 102 | 103 | The project requires the `gitlab-license` gem, which will be automatically downloaded and used by the script. 104 | 105 | ```bash 106 | gem install gitlab-license 107 | ``` 108 | 109 | ### Steps to Generate the GitLab License 110 | 111 | #### 1. Clone the project repository 112 | 113 | Clone this project to your local machine. 114 | 115 | ```bash 116 | git clone https://github.com/Lakr233/GitLab-License-Generator.git 117 | cd GitLab-License-Generator 118 | ``` 119 | 120 | #### 2. Run the `make.sh` script 121 | 122 | Once all the prerequisites are met, run the script: 123 | 124 | ```bash 125 | chmod +x src/scan.features.rb 126 | LICENSE_NAME="Tim Cook" 127 | LICENSE_COMPANY="Apple Computer, Inc." 128 | LICENSE_EMAIL="tcook@apple.com" 129 | LICENSE_PLAN="ultimate" 130 | LICENSE_USER_COUNT="2147483647" 131 | LICENSE_EXPIRE_YEAR="2500" 132 | ./make.sh 133 | ``` 134 | 135 | The script will perform the following actions: 136 | 137 | - Download and extract the `gitlab-license` gem. 138 | - Copy and modify the required files. 139 | - Clone the GitLab source code from GitLab.com. 140 | - Generate a public/private key pair. 141 | - Generate a GitLab license. 142 | 143 | #### 3. Replace the public key in GitLab 144 | 145 | The script generates a public key located in `build/public.key`. You need to replace GitLab’s existing public key with this newly generated one to ensure the license is accepted. 146 | 147 | - **If GitLab is installed on your server**: 148 | 149 | ```bash 150 | sudo cp ./build/public.key /opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub 151 | sudo gitlab-ctl reconfigure 152 | sudo gitlab-ctl restart 153 | ``` 154 | 155 | - **If GitLab is installed via Docker**: 156 | Modify your `docker-compose.yml` file to mount the new public key inside the container: 157 | 158 | ```yaml 159 | volumes: 160 | - "./build/public.key:/opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub" 161 | ``` 162 | 163 | Then restart the container: 164 | 165 | ```bash 166 | docker-compose down 167 | docker-compose up -d 168 | ``` 169 | 170 | #### 4. Install the license in GitLab 171 | 172 | Once the public key is replaced, log in to GitLab’s admin interface to install the generated license. 173 | 174 | 1. Log in to GitLab as an administrator. 175 | 2. Navigate to the **Admin Area** from the bottom-left corner. 176 | 3. Go to **Settings > General** and upload the generated license file (`build/result.gitlab-license`). 177 | 4. Check the **Terms of Service** checkbox and click **Add License**. 178 | 179 | If necessary, you can directly access the license upload page via: 180 | 181 | ``` 182 | /admin/license/new 183 | ``` 184 | 185 | #### 5. Disable Service Ping (optional) 186 | 187 | If you want to disable GitLab’s usage data collection (Service Ping), modify GitLab’s configuration file: 188 | 189 | - Open the configuration file: 190 | 191 | ```bash 192 | sudo nano /etc/gitlab/gitlab.rb 193 | ``` 194 | 195 | - Add the following line: 196 | 197 | ```bash 198 | gitlab_rails['usage_ping_enabled'] = false 199 | ``` 200 | 201 | - Reconfigure and restart GitLab: 202 | 203 | ```bash 204 | sudo gitlab-ctl reconfigure 205 | sudo gitlab-ctl restart 206 | ``` 207 | 208 | ### Troubleshooting 209 | 210 | - **HTTP 502 Error**: 211 | If you encounter this error, wait for GitLab to finish starting up (it may take some time). 212 | 213 | ## LICENSE 214 | 215 | This project is licensed under the **WTFPL License**. 216 | 217 | Copyright (c) 2023, Tim Cook, All Rights Not Reserved. 218 | -------------------------------------------------------------------------------- /keys/private.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAreEfP/ncA1A5cuxBz7rS0Z9DDxdSymLwt2OUSM5WJa+dVB3z 3 | SpQjinifdNZq+iHVt8toZBZZ02H3unbn8td0rIifoj4oVpLhvnOAVjUn5tZeUX17 4 | tWMA+yyBpf6w6IFxeYBXFd14WOKEarS05U9B59DjBxNqSm+GzhljHO7vvTKy2xXQ 5 | Q7Fa702DZ7jwr4DJnL87bDXfarnYksuawqtKwQbFHAOvxFj8ghBh1Gshap1abExD 6 | 4l7QWxFMTCVOkLJmXiqfOi5KuMiaMsSUsCBNQDE3A5aKvpwLGozsvpGRMy5Tt4Sg 7 | HC7ZbgerBNe75olOoPDxZf7bBt0+O5A/UjK/HwIDAQABAoIBACb3f4hX112KugUu 8 | OyVxidNebKnSIUSn3ahLkayrSRUTASAbwi0he8GJfLqzXrAFqx6QYCml9KVxnBHW 9 | me6LKGOODrBOW73jFuIWgllPeky6F9MNWw7wTAT+GWP46u6AK8z93QZSZqkMwn4j 10 | VzLYiz2HS4mHaVebHMvNVq/iQCnW9ztZnsv9HSoFt2WY2Cm/9UpAtbqrWRQTVnCt 11 | F7E1M9KICUKyM13qOQe+d0sZWx6D8eKrFlPs4KDXATs2SuDsaWpmWj9G8alSeHEW 12 | Ut+2MsS5BYNIVaG0KqDFRKDyTkhXzevz98r5KylFqfAB2bCnaqIE0hdOXfYd+CR0 13 | wwRAQmECgYEA1CnEO0K+nU8tZUwdTkL3wvo6z2jEnA97Laay9D/fnAjd3q8niTyJ 14 | 2DZQJp9omTa51/7EJw6YWhYdk078ZckwebWQPtXsA7MCTXSXL3+sGmL2GohDUovH 15 | G6zdn9sKws+U6tIOoEOMCLivEtmNM7HJXP3PViQr+rOUQV3ig/8v+s8CgYEA0c5c 16 | Or0Ta4apaM8aD6rP2Eilb3VC8AOvSzY36gN38ki/SwVH1ZTw/hbOYlQTsnk+OkXX 17 | 205k9tc78+9GrcYSuupjqzEdZVRQSGSbT9qXMMYfM3wK2Z7i37Cehn4Qw4BOOlgR 18 | TvsvBd0FSnzVi2wAkhx0zL1hNUXHHAYnVdOxyrECgYEAwKbkb0NePw4ElLUW71fU 19 | DxKVkHz7+xH7sipq2WueqttKTMkTx4RXTyOSiF+75VRSURYgG68fHL50QK06d1rH 20 | T91UjBpIY9uKvbafChyOtK8j9lfBehU+yZyg6mVGUjuYZ9oyOcjcQZciMqWlmEla 21 | Jby7JudVoCKs/uY3p9BzSvUCgYAF7Pkn44033T7NqgPHa4ChUDPz+PDiDIiX7Dka 22 | D+0EV8+nU8fanXFNC+HaXxuLT+dVCAH3vLgXTK7xzdFGOTDwPIyCGkoFQaNe2BCW 23 | 6cqZYw8giiFYUieAP+HKVKcujmInPbOHcoq6dKqglvQFExDVD56w5axoL8dW4Eme 24 | H/OGkQKBgHgQeK29Ntz7LcKlXYhQPkmYn+DWAmEq4J6XjjXyCV82HgEMmhIiAKKI 25 | UURKt4j6c7KSiAhnyITz9JeVRoAFVB3y/tSSc5E+CH3jG/G0YlToW20Itf6o8hwD 26 | XERkPPwsXVoZWR2FcUzcO7Bspm/JvkuaL+4u1fi+eNl7uF7RRaD1 27 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /keys/public.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAreEfP/ncA1A5cuxBz7rS 3 | 0Z9DDxdSymLwt2OUSM5WJa+dVB3zSpQjinifdNZq+iHVt8toZBZZ02H3unbn8td0 4 | rIifoj4oVpLhvnOAVjUn5tZeUX17tWMA+yyBpf6w6IFxeYBXFd14WOKEarS05U9B 5 | 59DjBxNqSm+GzhljHO7vvTKy2xXQQ7Fa702DZ7jwr4DJnL87bDXfarnYksuawqtK 6 | wQbFHAOvxFj8ghBh1Gshap1abExD4l7QWxFMTCVOkLJmXiqfOi5KuMiaMsSUsCBN 7 | QDE3A5aKvpwLGozsvpGRMy5Tt4SgHC7ZbgerBNe75olOoPDxZf7bBt0+O5A/UjK/ 8 | HwIDAQAB 9 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /lang/README_FR.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # GitLab License Generator 4 | 5 |

6 | English 7 |

8 | 9 |
10 | 11 | ## Description 12 | 13 | **GitLab License Generator** Ce projet permet de générer une licence GitLab à des **fins de développement**. Si vous rencontrez des problèmes, merci de les résoudre par vous-même. 14 | 15 | Dernier test effectué sur GitLab v17.5.1-ee. 16 | 17 | ## Principes 18 | 19 | ### **src/generator.keys.rb** 20 | 21 | GitLab utilise une paire de clés publique/privée pour chiffrer sa licence. La clé publique est fournie avec la distribution GitLab, tandis que la clé privée est conservée de manière sécurisée. La licence est simplement un dictionnaire JSON. Comme GitLab a rendu son code open-source, il est facile de générer sa propre licence. 22 | 23 | ### **src/generator.license.rb** 24 | 25 | Le dossier `lib` est extrait du code source de GitLab. Il est utilisé pour générer et valider la licence. Le script `src/generator.license.rb` le charge pour effectuer cette tâche. 26 | 27 | ### **src/scan.features.rb** 28 | 29 | **Ce fichier a été retiré suite à une demande de retrait DMCA.** 30 | 31 | ~~Les fonctionnalités sont extraites d'un objet contenant des constantes. Le plan le plus complet est **Ultimate**, mais des fonctionnalités comme le Geo Mirroring ne sont incluses dans aucun plan standard. Nous les ajoutons donc manuellement.~~ 32 | 33 | ## Utilisation 34 | 35 | ### Prérequis 36 | 37 | Avant de commencer, assurez-vous que votre environnement est correctement configuré. 38 | 39 | #### 1. Installer Ruby et gem 40 | Pour exécuter ce projet, vous devez installer **Ruby** et le gestionnaire de paquets **gem**. 41 | 42 | - **Sous Linux (Ubuntu/Debian)** : 43 | ```bash 44 | sudo apt update 45 | sudo apt install ruby-full 46 | ``` 47 | 48 | - **Sous macOS** (via Homebrew) : 49 | ```bash 50 | brew install ruby 51 | ``` 52 | 53 | #### 2. Installer Bundler et les gems nécessaires 54 | Une fois Ruby installé, vous devez installer **Bundler** pour gérer les dépendances Ruby. 55 | 56 | ```bash 57 | gem install bundler 58 | ``` 59 | 60 | #### 3. Installer le gem `gitlab-license` 61 | Le projet nécessite le gem `gitlab-license`, qui sera automatiquement téléchargé et utilisé par le script. 62 | 63 | ```bash 64 | gem install gitlab-license 65 | ``` 66 | 67 | ### Étapes pour générer la licence GitLab 68 | 69 | #### 1. Cloner le dépôt du projet 70 | Clonez ce projet sur votre machine locale. 71 | 72 | ```bash 73 | git clone https://github.com/Lakr233/GitLab-License-Generator.git 74 | cd GitLab-License-Generator 75 | ``` 76 | 77 | #### 2. Exécuter le script `make.sh` 78 | Une fois que tous les prérequis sont en place, exécutez le script : 79 | 80 | ```bash 81 | ./make.sh 82 | ``` 83 | 84 | Le script effectuera les actions suivantes : 85 | - Téléchargement et extraction du gem `gitlab-license`. 86 | - Copie et modification des fichiers nécessaires. 87 | - Clonage du code source GitLab depuis GitLab.com. 88 | - Génération d’une paire de clés publique/privée. 89 | - Génération d’une licence GitLab. 90 | 91 | #### 3. Remplacer la clé publique dans GitLab 92 | Le script génère une clé publique dans le fichier `build/public.key`. Vous devez remplacer la clé publique utilisée par GitLab avec celle générée pour que la licence soit acceptée. 93 | 94 | - **Si GitLab est installé sur votre serveur** : 95 | ```bash 96 | sudo cp ./build/public.key /opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub 97 | sudo gitlab-ctl reconfigure 98 | sudo gitlab-ctl restart 99 | ``` 100 | 101 | - **Si GitLab est installé via Docker** : 102 | Modifiez votre fichier `docker-compose.yml` pour monter la nouvelle clé publique dans le conteneur : 103 | 104 | ```yaml 105 | volumes: 106 | - "./build/public.key:/opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub" 107 | ``` 108 | 109 | Puis redémarrez le conteneur : 110 | ```bash 111 | docker-compose down 112 | docker-compose up -d 113 | ``` 114 | 115 | #### 4. Installer la licence dans GitLab 116 | Une fois la clé publique remplacée, connectez-vous à l'interface d'administration de GitLab pour installer la licence générée. 117 | 118 | 1. Connectez-vous à GitLab en tant qu’administrateur. 119 | 2. Accédez à **Admin Area** via le coin supérieur droit. 120 | 3. Allez dans **Settings > General** et téléchargez le fichier de licence généré (`build/result.gitlab-license`). 121 | 4. Cochez la case **Terms of Service** et cliquez sur **Add License**. 122 | 123 | Si nécessaire, accédez directement à la page de téléchargement de la licence via : 124 | ``` 125 | /admin/license/new 126 | ``` 127 | 128 | #### 5. Désactiver Service Ping (optionnel) 129 | Si vous souhaitez désactiver la collecte de données d'utilisation par GitLab (Service Ping), modifiez le fichier de configuration GitLab : 130 | 131 | - Ouvrez le fichier de configuration : 132 | ```bash 133 | sudo nano /etc/gitlab/gitlab.rb 134 | ``` 135 | 136 | - Ajoutez la ligne suivante : 137 | ```bash 138 | gitlab_rails['usage_ping_enabled'] = false 139 | ``` 140 | 141 | - Reconfigurez et redémarrez GitLab : 142 | ```bash 143 | sudo gitlab-ctl reconfigure 144 | sudo gitlab-ctl restart 145 | ``` 146 | 147 | ### Résolution des problèmes 148 | 149 | - **Erreur HTTP 502** : 150 | Si vous obtenez cette erreur, patientez simplement, car GitLab peut mettre du temps à démarrer. 151 | 152 | ## LICENCE 153 | 154 | Ce projet est sous licence **WTFPL License**. 155 | 156 | Copyright (c) 2023, Tim Cook, All Rights Not Reserved. 157 | -------------------------------------------------------------------------------- /lang/README_RU.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # Генератор лицензий GitLab 4 | 5 |

6 | English 7 |

8 | 9 |
10 | 11 | ## Описание 12 | 13 | **GitLab License Generator** Этот проект генерирует лицензию GitLab для **целей разработки**. Если у вас возникнут какие-либо проблемы, пожалуйста, устраните их самостоятельно. 14 | 15 | > [Последнее тестирование](../README.md). 16 | 17 | ## Принципы 18 | 19 | ### **src/generator.keys.rb** 20 | 21 | GitLab использует пару открытого/закрытого ключа для шифрования своей лицензии. Открытый ключ поставляется с дистрибутивом GitLab, а закрытый ключ хранится в безопасности. Сама лицензия представляет собой просто словарь JSON. Поскольку GitLab сделал свой код открытым, мы можем легко сгенерировать собственную лицензию. 22 | 23 | ### **src/generator.license.rb** 24 | 25 | Папка `lib` извлекается из исходного кода GitLab. Она используется для сборки и проверки лицензии. Скрипт `src/generator.license.rb` загружает эту функциональность. 26 | 27 | ### **src/scan.features.rb** 28 | 29 | **Этот файл был удален по запросу на удаление DMCA.** 30 | 31 | ~~Функции извлекаются из объекта, заполненного константами. Самый полный план лицензии — **Ultimate**, но такие функции, как Geo Mirroring, не включены ни в один стандартный план. Поэтому мы вручную добавляем эти функции.~~ 32 | 33 | ## Использование 34 | 35 | ### Предпосылки 36 | 37 | Перед началом убедитесь, что ваша среда правильно настроена. 38 | 39 | #### 1. Установите Ruby и gem 40 | Для запуска этого проекта вам понадобится **Ruby** и менеджер пакетов **gem**. 41 | 42 | - **В Linux (Ubuntu/Debian)**: 43 | ```bash 44 | sudo apt update 45 | sudo apt install ruby-full 46 | ``` 47 | 48 | - **На macOS** (через Homebrew): 49 | ```bash 50 | brew install ruby 51 | ``` 52 | 53 | #### 2. Установите Bundler и необходимые gems 54 | После установки Ruby вам необходимо установить **Bundler** для управления зависимостями Ruby. 55 | 56 | ```bash 57 | gem install bundler 58 | ``` 59 | 60 | #### 3. Установите gem `gitlab-license` 61 | Для проекта требуется gem `gitlab-license`, который будет автоматически загружен и использован скриптом. 62 | 63 | ```bash 64 | gem install gitlab-license 65 | ``` 66 | 67 | ### Шаги по созданию лицензии GitLab 68 | 69 | #### 1. Клонируйте репозиторий проекта 70 | Скопируйте этот проект на свой локальный компьютер. 71 | 72 | ```bash 73 | git clone https://github.com/Lakr233/GitLab-License-Generator.git 74 | cd GitLab-License-Generator 75 | ``` 76 | 77 | #### 2. Запустите скрипт `make.sh` 78 | После выполнения всех предварительных условий запустите скрипт: 79 | 80 | ```bash 81 | ./make.sh 82 | ``` 83 | 84 | Скрипт выполнит следующие действия: 85 | - Загрузит и распакует gem-файл `gitlab-license`. 86 | - Скопирует и изменит необходимые файлы. 87 | - Клонирует исходный код GitLab с GitLab.com. 88 | - Сгенерирует пару открытого и закрытого ключей. 89 | - Создаст лицензию GitLab. 90 | 91 | #### 3. Замена открытого ключа в GitLab 92 | Скрипт генерирует открытый ключ, расположенный в `build/public.key`. Вам необходимо заменить существующий открытый ключ GitLab на этот недавно сгенерированный, чтобы убедиться, что лицензия принята. 93 | 94 | - **Если на вашем сервере установлен GitLab**: 95 | ```bash 96 | sudo cp ./build/public.key /opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub 97 | sudo gitlab-ctl reconfigure 98 | sudo gitlab-ctl restart 99 | ``` 100 | 101 | - **Если GitLab установлен через Docker**: 102 | Измените файл `docker-compose.yml`, чтобы смонтировать новый открытый ключ внутрь контейнера: 103 | 104 | ```yaml 105 | volumes: 106 | - "./build/public.key:/opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub" 107 | ``` 108 | 109 | Затем перезапустите контейнер: 110 | ```bash 111 | docker-compose down 112 | docker-compose up -d 113 | ``` 114 | 115 | #### 4. Установите лицензию в GitLab 116 | После замены открытого ключа войдите в интерфейс администратора GitLab, чтобы установить сгенерированную лицензию. 117 | 118 | 1. Войдите в GitLab как администратор. 119 | 2. Перейдите в **Admin Area** из верхнего правого угла. 120 | 3. Перейдите в **Settings > General** и загрузите сгенерированный файл лицензии (`build/result.gitlab-license`). 121 | 4. Установите флажок **Terms of Service** и нажмите **Add License**. 122 | 123 | При необходимости вы можете напрямую перейти на страницу загрузки лицензии через: 124 | ``` 125 | /admin/license/new 126 | ``` 127 | 128 | #### 5. Отключить Service Ping (необязательно) 129 | Если вы хотите отключить сбор данных об использовании GitLab (Service Ping), измените файл конфигурации GitLab: 130 | 131 | - Откройте файл конфигурации: 132 | ```bash 133 | sudo nano /etc/gitlab/gitlab.rb 134 | ``` 135 | 136 | - Добавьте следующую строку: 137 | ```bash 138 | gitlab_rails['usage_ping_enabled'] = false 139 | ``` 140 | 141 | - Перенастройте и перезапустите GitLab: 142 | ```bash 143 | sudo gitlab-ctl reconfigure 144 | sudo gitlab-ctl restart 145 | ``` 146 | 147 | ### Поиск неисправностей 148 | 149 | - **Ошибка HTTP 502**: 150 | Если вы столкнулись с этой ошибкой, дождитесь завершения запуска GitLab (это может занять некоторое время). 151 | 152 | ## ЛИЦЕНЗИЯ 153 | 154 | Данный проект лицензирован по **WTFPL License**. 155 | 156 | Авторские права (c) 2023, Тим Кук, Все права не защищены. 157 | -------------------------------------------------------------------------------- /lib/license.rb: -------------------------------------------------------------------------------- 1 | require 'openssl' 2 | require 'date' 3 | require 'json' 4 | require 'base64' 5 | 6 | require_relative 'license/version' 7 | require_relative 'license/encryptor' 8 | require_relative 'license/boundary' 9 | 10 | module Gitlab 11 | class License 12 | class Error < StandardError; end 13 | class ImportError < Error; end 14 | class ValidationError < Error; end 15 | 16 | class << self 17 | attr_reader :encryption_key 18 | attr_reader :fallback_decryption_keys 19 | @encryption_key = nil 20 | 21 | def encryption_key=(key) 22 | raise ArgumentError, 'No RSA encryption key provided.' if key && !key.is_a?(OpenSSL::PKey::RSA) 23 | 24 | @encryption_key = key 25 | @encryptor = nil 26 | end 27 | 28 | def fallback_decryption_keys=(keys) 29 | unless keys 30 | @fallback_decryption_keys = nil 31 | return 32 | end 33 | 34 | unless keys.is_a?(Enumerable) && keys.all? { |key| key.is_a?(OpenSSL::PKey::RSA) } 35 | raise ArgumentError, 'Invalid fallback RSA encryption keys provided.' 36 | end 37 | 38 | @fallback_decryption_keys = Array(keys) 39 | end 40 | 41 | def encryptor 42 | @encryptor ||= Encryptor.new(encryption_key) 43 | end 44 | 45 | def import(data) 46 | raise ImportError, 'No license data.' if data.nil? 47 | 48 | data = Boundary.remove_boundary(data) 49 | 50 | license_json = decrypt_with_fallback_keys(data) 51 | 52 | begin 53 | attributes = JSON.parse(license_json) 54 | rescue JSON::ParseError 55 | raise ImportError, 'License data is invalid JSON.' 56 | end 57 | 58 | new(attributes) 59 | end 60 | 61 | def decrypt_with_fallback_keys(data) 62 | keys_to_try = Array(encryption_key) 63 | keys_to_try += fallback_decryption_keys if fallback_decryption_keys 64 | 65 | keys_to_try.each do |decryption_key| 66 | decryptor = Encryptor.new(decryption_key) 67 | return decryptor.decrypt(data) 68 | rescue Encryptor::Error 69 | next 70 | end 71 | 72 | raise ImportError, 'License data could not be decrypted.' 73 | end 74 | end 75 | 76 | attr_reader :version 77 | attr_accessor :licensee, :starts_at, :expires_at, :notify_admins_at, 78 | :notify_users_at, :block_changes_at, :last_synced_at, :next_sync_at, 79 | :activated_at, :restrictions, :cloud_licensing_enabled, 80 | :offline_cloud_licensing_enabled, :auto_renew_enabled, :seat_reconciliation_enabled, 81 | :operational_metrics_enabled, :generated_from_customers_dot, 82 | :generated_from_cancellation 83 | 84 | alias_method :issued_at, :starts_at 85 | alias_method :issued_at=, :starts_at= 86 | 87 | def initialize(attributes = {}) 88 | load_attributes(attributes) 89 | end 90 | 91 | def valid? 92 | if !licensee || !licensee.is_a?(Hash) || licensee.empty? 93 | false 94 | elsif !starts_at || !starts_at.is_a?(Date) 95 | false 96 | elsif !expires_at && !gl_team_license? && !jh_team_license? 97 | false 98 | elsif expires_at && !expires_at.is_a?(Date) 99 | false 100 | elsif notify_admins_at && !notify_admins_at.is_a?(Date) 101 | false 102 | elsif notify_users_at && !notify_users_at.is_a?(Date) 103 | false 104 | elsif block_changes_at && !block_changes_at.is_a?(Date) 105 | false 106 | elsif last_synced_at && !last_synced_at.is_a?(DateTime) 107 | false 108 | elsif next_sync_at && !next_sync_at.is_a?(DateTime) 109 | false 110 | elsif activated_at && !activated_at.is_a?(DateTime) 111 | false 112 | elsif restrictions && !restrictions.is_a?(Hash) 113 | false 114 | elsif !cloud_licensing? && offline_cloud_licensing? 115 | false 116 | else 117 | true 118 | end 119 | end 120 | 121 | def validate! 122 | raise ValidationError, 'License is invalid' unless valid? 123 | end 124 | 125 | def will_expire? 126 | expires_at 127 | end 128 | 129 | def will_notify_admins? 130 | notify_admins_at 131 | end 132 | 133 | def will_notify_users? 134 | notify_users_at 135 | end 136 | 137 | def will_block_changes? 138 | block_changes_at 139 | end 140 | 141 | def will_sync? 142 | next_sync_at 143 | end 144 | 145 | def activated? 146 | activated_at 147 | end 148 | 149 | def expired? 150 | will_expire? && Date.today >= expires_at 151 | end 152 | 153 | def notify_admins? 154 | will_notify_admins? && Date.today >= notify_admins_at 155 | end 156 | 157 | def notify_users? 158 | will_notify_users? && Date.today >= notify_users_at 159 | end 160 | 161 | def block_changes? 162 | will_block_changes? && Date.today >= block_changes_at 163 | end 164 | 165 | def cloud_licensing? 166 | cloud_licensing_enabled == true 167 | end 168 | 169 | def offline_cloud_licensing? 170 | offline_cloud_licensing_enabled == true 171 | end 172 | 173 | def auto_renew? 174 | auto_renew_enabled == true 175 | end 176 | 177 | def seat_reconciliation? 178 | seat_reconciliation_enabled == true 179 | end 180 | 181 | def operational_metrics? 182 | operational_metrics_enabled == true 183 | end 184 | 185 | def generated_from_customers_dot? 186 | generated_from_customers_dot == true 187 | end 188 | 189 | def generated_from_cancellation? 190 | generated_from_cancellation == true 191 | end 192 | 193 | def gl_team_license? 194 | licensee['Company'].to_s.match?(/GitLab/i) && licensee['Email'].to_s.end_with?('@gitlab.com') 195 | end 196 | 197 | def jh_team_license? 198 | licensee['Company'].to_s.match?(/GitLab/i) && licensee['Email'].to_s.end_with?('@jihulab.com') 199 | end 200 | 201 | def restricted?(key = nil) 202 | if key 203 | restricted? && restrictions.has_key?(key) 204 | else 205 | restrictions && restrictions.length >= 1 206 | end 207 | end 208 | 209 | def attributes 210 | hash = {} 211 | 212 | hash['version'] = version 213 | hash['licensee'] = licensee 214 | 215 | # `issued_at` is the legacy name for starts_at. 216 | # TODO: Move to starts_at in a next version. 217 | hash['issued_at'] = starts_at 218 | hash['expires_at'] = expires_at if will_expire? 219 | 220 | hash['notify_admins_at'] = notify_admins_at if will_notify_admins? 221 | hash['notify_users_at'] = notify_users_at if will_notify_users? 222 | hash['block_changes_at'] = block_changes_at if will_block_changes? 223 | 224 | hash['next_sync_at'] = next_sync_at if will_sync? 225 | hash['last_synced_at'] = last_synced_at if will_sync? 226 | hash['activated_at'] = activated_at if activated? 227 | 228 | hash['cloud_licensing_enabled'] = cloud_licensing? 229 | hash['offline_cloud_licensing_enabled'] = offline_cloud_licensing? 230 | hash['auto_renew_enabled'] = auto_renew? 231 | hash['seat_reconciliation_enabled'] = seat_reconciliation? 232 | hash['operational_metrics_enabled'] = operational_metrics? 233 | 234 | hash['generated_from_customers_dot'] = generated_from_customers_dot? 235 | hash['generated_from_cancellation'] = generated_from_cancellation? 236 | 237 | hash['restrictions'] = restrictions if restricted? 238 | 239 | hash 240 | end 241 | 242 | def to_json(*_args) 243 | JSON.dump(attributes) 244 | end 245 | 246 | def export(boundary: nil) 247 | validate! 248 | 249 | data = self.class.encryptor.encrypt(to_json) 250 | 251 | data = Boundary.add_boundary(data, boundary) if boundary 252 | 253 | data 254 | end 255 | 256 | private 257 | 258 | def load_attributes(attributes) 259 | attributes = attributes.transform_keys(&:to_s) 260 | 261 | version = attributes['version'] || 1 262 | raise ArgumentError, 'Version is too new' unless version && version == 1 263 | 264 | @version = version 265 | 266 | @licensee = attributes['licensee'] 267 | 268 | # `issued_at` is the legacy name for starts_at. 269 | # TODO: Move to starts_at in a next version. 270 | %w[issued_at expires_at notify_admins_at notify_users_at block_changes_at].each do |attr_name| 271 | set_date_attribute(attr_name, attributes[attr_name]) 272 | end 273 | 274 | %w[last_synced_at next_sync_at activated_at].each do |attr_name| 275 | set_datetime_attribute(attr_name, attributes[attr_name]) 276 | end 277 | 278 | %w[ 279 | cloud_licensing_enabled 280 | offline_cloud_licensing_enabled 281 | auto_renew_enabled 282 | seat_reconciliation_enabled 283 | operational_metrics_enabled 284 | generated_from_customers_dot 285 | generated_from_cancellation 286 | ].each do |attr_name| 287 | public_send("#{attr_name}=", attributes[attr_name] == true) 288 | end 289 | 290 | restrictions = attributes['restrictions'] 291 | if restrictions&.is_a?(Hash) 292 | restrictions = restrictions.transform_keys(&:to_sym) 293 | @restrictions = restrictions 294 | end 295 | end 296 | 297 | def set_date_attribute(attr_name, value, date_class = Date) 298 | value = date_class.parse(value) rescue nil if value.is_a?(String) 299 | 300 | return unless value 301 | 302 | public_send("#{attr_name}=", value) 303 | end 304 | 305 | def set_datetime_attribute(attr_name, value) 306 | set_date_attribute(attr_name, value, DateTime) 307 | end 308 | end 309 | end 310 | -------------------------------------------------------------------------------- /lib/license/boundary.rb: -------------------------------------------------------------------------------- 1 | module Gitlab 2 | class License 3 | module Boundary 4 | BOUNDARY_START = /(\A|\r?\n)-*BEGIN .+? LICENSE-*\r?\n/.freeze 5 | BOUNDARY_END = /\r?\n-*END .+? LICENSE-*(\r?\n|\z)/.freeze 6 | 7 | class << self 8 | def add_boundary(data, product_name) 9 | data = remove_boundary(data) 10 | 11 | product_name.upcase! 12 | 13 | pad = lambda do |message, width| 14 | total_padding = [width - message.length, 0].max 15 | 16 | padding = total_padding / 2.0 17 | [ 18 | '-' * padding.ceil, 19 | message, 20 | '-' * padding.floor 21 | ].join 22 | end 23 | 24 | [ 25 | pad.call("BEGIN #{product_name} LICENSE", 60), 26 | data.strip, 27 | pad.call("END #{product_name} LICENSE", 60) 28 | ].join("\n") 29 | end 30 | 31 | def remove_boundary(data) 32 | after_boundary = data.split(BOUNDARY_START).last 33 | in_boundary = after_boundary.split(BOUNDARY_END).first 34 | 35 | in_boundary 36 | end 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/license/encryptor.rb: -------------------------------------------------------------------------------- 1 | module Gitlab 2 | class License 3 | class Encryptor 4 | class Error < StandardError; end 5 | class KeyError < Error; end 6 | class DecryptionError < Error; end 7 | 8 | attr_accessor :key 9 | 10 | def initialize(key) 11 | raise KeyError, 'No RSA encryption key provided.' if key && !key.is_a?(OpenSSL::PKey::RSA) 12 | 13 | @key = key 14 | end 15 | 16 | def encrypt(data) 17 | raise KeyError, 'Provided key is not a private key.' unless key.private? 18 | 19 | # Encrypt the data using symmetric AES encryption. 20 | cipher = OpenSSL::Cipher::AES128.new(:CBC) 21 | cipher.encrypt 22 | aes_key = cipher.random_key 23 | aes_iv = cipher.random_iv 24 | 25 | encrypted_data = cipher.update(data) + cipher.final 26 | 27 | # Encrypt the AES key using asymmetric RSA encryption. 28 | encrypted_key = key.private_encrypt(aes_key) 29 | 30 | encryption_data = { 31 | 'data' => Base64.encode64(encrypted_data), 32 | 'key' => Base64.encode64(encrypted_key), 33 | 'iv' => Base64.encode64(aes_iv) 34 | } 35 | 36 | json_data = JSON.dump(encryption_data) 37 | Base64.encode64(json_data) 38 | end 39 | 40 | def decrypt(data) 41 | raise KeyError, 'Provided key is not a public key.' unless key.public? 42 | 43 | json_data = Base64.decode64(data.chomp) 44 | 45 | begin 46 | encryption_data = JSON.parse(json_data) 47 | rescue JSON::ParserError 48 | raise DecryptionError, 'Encryption data is invalid JSON.' 49 | end 50 | 51 | unless %w[data key iv].all? { |key| encryption_data[key] } 52 | raise DecryptionError, 'Required field missing from encryption data.' 53 | end 54 | 55 | encrypted_data = Base64.decode64(encryption_data['data']) 56 | encrypted_key = Base64.decode64(encryption_data['key']) 57 | aes_iv = Base64.decode64(encryption_data['iv']) 58 | 59 | begin 60 | # Decrypt the AES key using asymmetric RSA encryption. 61 | aes_key = self.key.public_decrypt(encrypted_key) 62 | rescue OpenSSL::PKey::RSAError 63 | raise DecryptionError, 'AES encryption key could not be decrypted.' 64 | end 65 | 66 | # Decrypt the data using symmetric AES encryption. 67 | cipher = OpenSSL::Cipher::AES128.new(:CBC) 68 | cipher.decrypt 69 | 70 | begin 71 | cipher.key = aes_key 72 | rescue OpenSSL::Cipher::CipherError 73 | raise DecryptionError, 'AES encryption key is invalid.' 74 | end 75 | 76 | begin 77 | cipher.iv = aes_iv 78 | rescue OpenSSL::Cipher::CipherError 79 | raise DecryptionError, 'AES IV is invalid.' 80 | end 81 | 82 | begin 83 | data = cipher.update(encrypted_data) + cipher.final 84 | rescue OpenSSL::Cipher::CipherError 85 | raise DecryptionError, 'Data could not be decrypted.' 86 | end 87 | 88 | data 89 | end 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /lib/license/version.rb: -------------------------------------------------------------------------------- 1 | module Gitlab 2 | class License 3 | VERSION = '2.4.0'.freeze 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "[i] GitLab License Generator" 4 | echo "[i] Copyright (c) 2023 Tim Cook, All Rights Not Reserved" 5 | LICENSE_NAME="${LICENSE_NAME:-"Tim Cook"}" 6 | LICENSE_COMPANY="${LICENSE_COMPANY:-"Apple Computer, Inc."}" 7 | LICENSE_EMAIL="${LICENSE_EMAIL:-"tcook@apple.com"}" 8 | LICENSE_PLAN="${LICENSE_PLAN:-ultimate}" 9 | LICENSE_USER_COUNT="${LICENSE_USER_COUNT:-2147483647}" 10 | LICENSE_EXPIRE_YEAR="${LICENSE_EXPIRE_YEAR:-2500}" 11 | set -e 12 | 13 | cd "$(dirname "$0")" 14 | if [ ! -f ".root" ]; then 15 | echo "[!] failed to locate project directory, aborting..." 16 | exit 1 17 | fi 18 | WORKING_DIR=$(pwd) 19 | 20 | mkdir temp 2>/dev/null || true 21 | 22 | echo "[*] fetching ruby gem version..." 23 | RB_GEM_NAME="gitlab-license" 24 | RB_GEM_LIST_OUTPUT=$(gem list --remote $RB_GEM_NAME) 25 | 26 | RB_GEM_VERSION="" 27 | while IFS= read -r line; do 28 | if [[ $line == "gitlab-license ("* ]]; then 29 | RB_GEM_VERSION=${line#"gitlab-license ("} 30 | RB_GEM_VERSION=${RB_GEM_VERSION%")"} 31 | break 32 | fi 33 | done <<<"$RB_GEM_LIST_OUTPUT" 34 | 35 | echo "[*] gitlab-license version: $RB_GEM_VERSION" 36 | RB_GEM_DOWNLOAD_URL="https://rubygems.org/downloads/gitlab-license-$RB_GEM_VERSION.gem" 37 | RB_GEM_DOWNLOAD_PATH=$(pwd)/temp/gem/gitlab-license.gem 38 | mkdir -p "$(dirname "$RB_GEM_DOWNLOAD_PATH")" 39 | curl -L "$RB_GEM_DOWNLOAD_URL" -o "$RB_GEM_DOWNLOAD_PATH" 1>/dev/null 2>/dev/null 40 | pushd "$(dirname "$RB_GEM_DOWNLOAD_PATH")" >/dev/null 41 | tar -xf gitlab-license.gem 42 | tar -xf data.tar.gz 43 | 44 | if [ ! -f "./lib/gitlab/license.rb" ]; then 45 | echo "[!] failed to locate gem file, aborting..." 46 | exit 1 47 | fi 48 | 49 | echo "[*] copying gem..." 50 | rm -rf "${WORKING_DIR:?}/lib" || true 51 | mkdir -p "$WORKING_DIR/lib" 52 | cp -r ./lib/gitlab/* "$WORKING_DIR/lib" 53 | popd >/dev/null 54 | 55 | pushd lib >/dev/null 56 | echo "[*] patching lib requirements gem..." 57 | 58 | # Determine the operating system 59 | OS_TYPE="$(uname -s)" 60 | 61 | case "$OS_TYPE" in 62 | Linux*) 63 | sed_i_cmd="sed -i" 64 | ;; 65 | Darwin*) 66 | sed_i_cmd="sed -i ''" 67 | ;; 68 | *) 69 | echo "Unsupported OS: $OS_TYPE" 70 | exit 1 71 | ;; 72 | esac 73 | 74 | # replace `require 'gitlab/license/` with `require 'license/` to make it work 75 | find . -type f -exec $sed_i_cmd 's/require '\''gitlab\/license\//require_relative '\''license\//g' {} \; 76 | 77 | popd >/dev/null 78 | 79 | echo "[*] updated gem" 80 | 81 | echo "[*] fetching gitlab source code..." 82 | GITLAB_SOURCE_CODE_DIR=$(pwd)/temp/src 83 | 84 | mkdir -p "$GITLAB_SOURCE_CODE_DIR" 85 | echo "[*] downloading features file..." 86 | curl -L https://gitlab.com/gitlab-org/gitlab/-/raw/master/ee/app/models/gitlab_subscriptions/features.rb?inline=false -o "$GITLAB_SOURCE_CODE_DIR/features.rb" 87 | 88 | BUILD_DIR=$(pwd)/build 89 | mkdir -p "$BUILD_DIR" 90 | 91 | echo "[*] scanning features..." 92 | FEATURE_LIST_FILE=$BUILD_DIR/features.json 93 | rm -f "${FEATURE_LIST_FILE:?}" || true 94 | ./src/scan.features.rb \ 95 | -o "$FEATURE_LIST_FILE" \ 96 | -f "$GITLAB_SOURCE_CODE_DIR/features.rb" 97 | 98 | echo "[*] generating key pair..." 99 | PUBLIC_KEY_FILE=$BUILD_DIR/public.key 100 | PRIVATE_KEY_FILE=$BUILD_DIR/private.key 101 | cp -f ./keys/public.key "$PUBLIC_KEY_FILE" 102 | cp -f ./keys/private.key "$PRIVATE_KEY_FILE" 103 | 104 | # execute following command to generate new keys 105 | # ./src/generator.keys.rb \ 106 | # --public-key $PUBLIC_KEY_FILE \ 107 | # --private-key $PRIVATE_KEY_FILE 108 | 109 | echo "[*] generating license..." 110 | LICENSE_FILE=$BUILD_DIR/result.gitlab-license 111 | LICENSE_JSON_FILE=$BUILD_DIR/license.json 112 | 113 | ./src/generator.license.rb \ 114 | -f "$FEATURE_LIST_FILE" \ 115 | --public-key "$PUBLIC_KEY_FILE" \ 116 | --private-key "$PRIVATE_KEY_FILE" \ 117 | -o "$LICENSE_FILE" \ 118 | --license-name "$LICENSE_NAME" \ 119 | --license-company "$LICENSE_COMPANY" \ 120 | --license-email "$LICENSE_EMAIL" \ 121 | --license-plan "$LICENSE_PLAN" \ 122 | --license-user-count "$LICENSE_USER_COUNT" \ 123 | --license-expire-year "$LICENSE_EXPIRE_YEAR" \ 124 | --plain-license "$LICENSE_JSON_FILE" 125 | 126 | echo "[*] done $(basename "$0")" 127 | -------------------------------------------------------------------------------- /src/generator.keys.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require 'optparse' 5 | require 'openssl' 6 | 7 | public_key_file = nil 8 | private_key_file = nil 9 | 10 | OptionParser.new do |opts| 11 | opts.banner = "Usage: generator.keys.rb [options]" 12 | 13 | opts.on("--public-key PATH", "Specify public key file (required)") do |v| 14 | public_key_file = File.expand_path(v) 15 | end 16 | 17 | opts.on("--private-key PATH", "Specify private key file (required)") do |v| 18 | private_key_file = File.expand_path(v) 19 | end 20 | 21 | opts.on("-h", "--help", "Prints this help") do 22 | puts opts 23 | exit 24 | end 25 | end.parse! 26 | 27 | if public_key_file.nil? || private_key_file.nil? 28 | puts "[!] missing required options" 29 | puts "[!] use -h for help" 30 | exit 1 31 | end 32 | 33 | if File.exist?(private_key_file) || File.exist?(public_key_file) 34 | puts "[!] key pair already exists" 35 | puts "[!] remove them if you want to regenerate" 36 | exit 1 37 | end 38 | 39 | puts "[*] generating rsa key pair..." 40 | key = OpenSSL::PKey::RSA.new(2048) 41 | File.write(private_key_file, key.to_pem) 42 | File.write(public_key_file, key.public_key.to_pem) 43 | 44 | puts "[*] done" 45 | -------------------------------------------------------------------------------- /src/generator.license.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | license_file_path = nil 5 | license_json_path = nil 6 | public_key_path = nil 7 | private_key_path = nil 8 | features_json_path = nil 9 | license_name="Tim Cook" 10 | license_company="Apple Computer, Inc." 11 | license_email="tcook@apple.com" 12 | license_plan='ultimate' 13 | license_user_count=2147483647 14 | license_expire_year=2500 15 | 16 | require 'optparse' 17 | OptionParser.new do |opts| 18 | opts.banner = "Usage: generator.license.rb [options]" 19 | 20 | opts.on("-o", "--output PATH", "Output to dir (required)") do |v| 21 | license_file_path = File.expand_path(v) 22 | end 23 | 24 | opts.on("--public-key PATH", "Specify public key file (required)") do |v| 25 | public_key_path = File.expand_path(v) 26 | end 27 | 28 | opts.on("--private-key PATH", "Specify private key file (required)") do |v| 29 | private_key_path = File.expand_path(v) 30 | end 31 | 32 | opts.on("-f", "--features PATH", "Specify features json file (optional)") do |v| 33 | features_json_path = File.expand_path(v) 34 | end 35 | 36 | opts.on("--plain-license PATH", "Export license in json if set, useful for debug. (optional)") do |v| 37 | license_json_path = File.expand_path(v) 38 | end 39 | 40 | opts.on("--license-name NAME", "Specify license name (optional) [#{license_name}]") do |v| 41 | license_name = v 42 | end 43 | 44 | opts.on("--license-company COMPANY", "Specify license company (optional) [#{license_company}]") do |v| 45 | license_company = v 46 | end 47 | 48 | opts.on("--license-email EMAIL-ADDRESS", "Specify license email address (optional) [#{license_email}]") do |v| 49 | license_email = v 50 | end 51 | 52 | opts.on("--license-plan PLAN", "Specify license plan (optional) [#{license_plan} (default), premium, starter]") do |v| 53 | license_plan = v 54 | end 55 | 56 | opts.on("--license-user-count COUNT", "Specify license user count (optional) [#{license_user_count} (default)]") do |v| 57 | license_user_count = v.to_i 58 | end 59 | 60 | opts.on("--license-expire-year YEAR", "Specify license expire year (optional) [#{license_expire_year} (default)]") do |v| 61 | license_expire_year = v.to_i 62 | end 63 | 64 | opts.on("-h", "--help", "Prints this help") do 65 | puts opts 66 | exit 67 | end 68 | end 69 | .parse! 70 | 71 | if license_file_path.nil? || public_key_path.nil? || private_key_path.nil? 72 | puts "[!] missing required options" 73 | puts "[!] use -h for help" 74 | exit 1 75 | end 76 | 77 | if license_plan != 'ultimate' && license_plan != 'premium' && license_plan != 'starter' 78 | puts "[!] license plan is set to #{license_plan} which is not one of [ultimate, premium, starter]" 79 | puts "[!] use -h for help" 80 | exit 1 81 | end 82 | 83 | if Time.now.year > license_expire_year 84 | puts "[!] license expiry year is set to #{license_expire_year} which is less than current year, this value must be greater than current year" 85 | puts "[!] use -h for help" 86 | exit 1 87 | end 88 | 89 | if license_user_count < 1 90 | puts "[!] license user count is set to #{license_user_count} which is less minumum user count possible" 91 | puts "[!] use -h for help" 92 | exit 1 93 | end 94 | 95 | # ========== 96 | 97 | puts "[*] loading keys..." 98 | require 'openssl' 99 | PUBLIC_KEY = OpenSSL::PKey::RSA.new File.read(public_key_path) 100 | PRIVATE_KEY = OpenSSL::PKey::RSA.new File.read(private_key_path) 101 | 102 | puts "[*] loading licenses..." 103 | require_relative '../lib/license.rb' 104 | puts "[i] lib gitlab-license: #{Gitlab::License::VERSION}" 105 | 106 | if !features_json_path.nil? 107 | puts "[*] loading features from #{features_json_path}" 108 | require 'json' 109 | FEATURE_LIST = JSON.parse(File.read(features_json_path)) 110 | else 111 | FEATURE_LIST = [] 112 | end 113 | puts "[*] total features to inject: #{FEATURE_LIST.size}" 114 | 115 | # ========== 116 | 117 | puts "[*] building a license..." 118 | 119 | Gitlab::License.encryption_key = PRIVATE_KEY 120 | 121 | license = Gitlab::License.new 122 | 123 | # don't use gitlab inc, search `gl_team_license` in lib for details 124 | license.licensee = { 125 | "Name" => license_name, 126 | "Company" => license_company, 127 | "Email" => license_email 128 | } 129 | 130 | # required of course 131 | license.starts_at = Date.new(1976, 4, 1) 132 | puts Date.new() 133 | # required since gem gitlab-license v2.2.1 134 | license.expires_at = Date.new(license_expire_year, 4, 1) 135 | 136 | # prevent gitlab crash at 137 | # notification_start_date = trial? ? expires_at - NOTIFICATION_DAYS_BEFORE_TRIAL_EXPIRY : block_changes_at 138 | license.block_changes_at = Date.new(license_expire_year, 4, 1) 139 | 140 | # required 141 | license.restrictions = { 142 | plan: license_plan, 143 | # STARTER_PLAN = 'starter' 144 | # PREMIUM_PLAN = 'premium' 145 | # ULTIMATE_PLAN = 'ultimate' 146 | 147 | active_user_count: license_user_count, 148 | # required, just dont overflow 149 | } 150 | 151 | license.cloud_licensing_enabled = true 152 | license.offline_cloud_licensing_enabled = true 153 | 154 | # restricted_attr will access restrictions 155 | # add_ons will access restricted_attr(:add_ons, {}) 156 | # so here by we inject all features into restrictions 157 | # see scan.rb for a list of features that we are going to inject 158 | for feature in FEATURE_LIST 159 | license.restrictions[feature] = license_user_count 160 | end 161 | 162 | puts "[*] validating license..." 163 | if !license.valid? 164 | puts "[E] license validation failed!" 165 | puts "[E] #{license.errors}" 166 | exit 1 167 | end 168 | puts "[*] license validated" 169 | 170 | puts "[*] exporting license file..." 171 | 172 | if !license_json_path.nil? 173 | puts "[*] writing to #{license_json_path}" 174 | File.write(license_json_path, JSON.pretty_generate(JSON.parse(license.to_json))) 175 | end 176 | 177 | puts "[*] writing to #{license_file_path}" 178 | File.write(license_file_path, license.export) 179 | 180 | puts "[*] done" 181 | -------------------------------------------------------------------------------- /src/modify.license.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | require 'base64' 5 | require 'json' 6 | require 'openssl' 7 | require 'tempfile' 8 | require 'optparse' 9 | require_relative '../lib/license/encryptor' 10 | 11 | public_key_path = nil 12 | in_file = nil 13 | 14 | OptionParser.new do |opts| 15 | opts.banner = "Usage: xxx.rb [options]" 16 | 17 | opts.on("-k", "--public-key PATH", "Specify public key file (required)") do |v| 18 | public_key_path = File.expand_path(v) 19 | end 20 | 21 | opts.on("-i", "--in PATH", "input license path") do |v| 22 | in_file = File.expand_path(v) 23 | end 24 | 25 | opts.on("-h", "--help", "Prints this help") do 26 | puts opts 27 | exit 28 | end 29 | end 30 | .parse! 31 | 32 | if in_file.nil? || public_key_path.nil? 33 | puts "[!] missing required options" 34 | puts "[!] use -h for help" 35 | exit 1 36 | end 37 | 38 | content = File.read(in_file) 39 | attributes = JSON.parse(Base64.decode64(content)) 40 | 41 | PUBLIC_KEY = OpenSSL::PKey::RSA.new File.read(public_key_path) 42 | decryptor = Gitlab::License::Encryptor.new(PUBLIC_KEY) 43 | plain_license = decryptor.decrypt(content) 44 | edited_json = nil 45 | 46 | Tempfile.create(['json_edit', '.json']) do |file| 47 | file.write(JSON.pretty_generate(JSON.parse(plain_license))) 48 | file.flush 49 | 50 | system("vim #{file.path}") 51 | file.rewind 52 | edited_json = file.read 53 | end 54 | 55 | edited_json = JSON.generate(JSON.parse(edited_json)) 56 | 57 | cipher = OpenSSL::Cipher::AES128.new(:CBC) 58 | cipher.encrypt 59 | cipher.key = PUBLIC_KEY.public_decrypt(Base64.decode64(attributes['key'])) 60 | cipher.iv = Base64.decode64(attributes['iv']) 61 | 62 | encrypted_data = cipher.update(edited_json) + cipher.final 63 | 64 | encryption_data = { 65 | 'data' => Base64.encode64(encrypted_data), 66 | 'key' => attributes['key'], 67 | 'iv' => attributes['iv'] 68 | } 69 | 70 | json_data = JSON.dump(encryption_data) 71 | puts Base64.encode64(json_data) 72 | -------------------------------------------------------------------------------- /src/scan.features.rb: -------------------------------------------------------------------------------- 1 | # #!/usr/bin/env ruby 2 | # # encoding: utf-8 3 | 4 | # require 'json' 5 | # require 'optparse' 6 | 7 | # # 8 | # # this file was removed due to DMCA report 9 | # # following action was taken 10 | # # https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository 11 | # # 12 | 13 | # OptionParser.new do |opts| 14 | # opts.banner = "Usage: scan.features.rb [options]" 15 | 16 | # opts.on("-s", "--src-dir PATH", "") do |v| 17 | # # empty block 18 | # end 19 | 20 | # opts.on("-f", "--features-file PATH", "") do |v| 21 | # # empty block 22 | # end 23 | 24 | # opts.on("-o", "--output PATH", "Output to json file (required)") do |v| 25 | # EXPORT_JSON_FILE = File.expand_path(v) 26 | # end 27 | 28 | # opts.on("-h", "--help", "Prints this help") do 29 | # puts opts 30 | # exit 31 | # end 32 | # end 33 | # .parse! 34 | 35 | # File.open(EXPORT_JSON_FILE, 'w') { |file| file.write("{}") } 36 | #!/usr/bin/env ruby 37 | # encoding: utf-8 38 | 39 | require 'json' 40 | require 'optparse' 41 | 42 | OptionParser.new do |opts| 43 | opts.banner = "Usage: scan.features.rb [options]" 44 | 45 | opts.on("-s", "--src-dir PATH", "Specify gitlab source dir (required if --features-file is ommited)") do |v| 46 | GITLAB_FEATURES_FILE="#{File.expand_path(v)}/ee/app/models/gitlab_subscriptions/features.rb" 47 | end 48 | 49 | opts.on("-f", "--features-file PATH", "Specify gitlab features path (required if --src-dir is ommited)") do |v| 50 | GITLAB_FEATURES_FILE = File.expand_path(v) 51 | end 52 | 53 | opts.on("-o", "--output PATH", "Output to json file (required)") do |v| 54 | EXPORT_JSON_FILE = File.expand_path(v) 55 | end 56 | 57 | opts.on("-h", "--help", "Prints this help") do 58 | puts opts 59 | exit 60 | end 61 | end 62 | .parse! 63 | if GITLAB_FEATURES_FILE.nil? || EXPORT_JSON_FILE.nil? 64 | puts "[!] missing required options" 65 | puts "[!] use -h for help" 66 | exit 1 67 | end 68 | puts "Reading features from #{GITLAB_FEATURES_FILE}" 69 | 70 | def ignore_exception 71 | begin 72 | yield 73 | rescue Exception 74 | end 75 | end 76 | 77 | puts "[*] loading features.rb..." 78 | ignore_exception do 79 | require_relative "#{GITLAB_FEATURES_FILE}" 80 | end 81 | 82 | ALL_FEATURES = [] 83 | GitlabSubscriptions::Features.constants.each do |const_name| 84 | puts "[*] gathering features from #{const_name}" 85 | if const_name.to_s.include? 'FEATURE' 86 | ALL_FEATURES.concat(GitlabSubscriptions::Features.const_get(const_name)) 87 | else 88 | puts "[?] unrecognized constant #{const_name}" 89 | end 90 | end 91 | 92 | ALL_FEATURES.uniq! 93 | ALL_FEATURES.sort_by! { |feature| feature } 94 | 95 | puts "[*] total features: #{ALL_FEATURES.size}" 96 | 97 | puts "[*] writing to #{EXPORT_JSON_FILE}" 98 | File.write(EXPORT_JSON_FILE, JSON.pretty_generate(ALL_FEATURES)) 99 | 100 | puts "[*] done" 101 | --------------------------------------------------------------------------------