init
This commit is contained in:
commit
c8401373a2
21 changed files with 1589 additions and 0 deletions
6
.dockerignore
Normal file
6
.dockerignore
Normal file
|
@ -0,0 +1,6 @@
|
|||
langs/
|
||||
README.md
|
||||
LICENSE
|
||||
.github/
|
||||
Dockerfile
|
||||
.*ignore
|
0
.github/.gitkeep
vendored
Normal file
0
.github/.gitkeep
vendored
Normal file
25
.github/workflows/build.yml
vendored
Normal file
25
.github/workflows/build.yml
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
name: Ruby Gem
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
schedule:
|
||||
- cron: "0 1 * * *"
|
||||
|
||||
jobs:
|
||||
rebuild:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout Source Code
|
||||
uses: actions/checkout@v4
|
||||
- name: Build
|
||||
run: |
|
||||
./make.sh
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build
|
||||
path: build
|
47
.github/workflows/docker-image.yml
vendored
Normal file
47
.github/workflows/docker-image.yml
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
# GitHub recommends pinning actions to a commit SHA.
|
||||
# To get a newer version, you will need to update the SHA.
|
||||
# You can also reference a tag or branch, but the action may change without warning.
|
||||
|
||||
name: Publish Container to Github at dev
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build-and-push-image:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
64
.gitignore
vendored
Normal file
64
.gitignore
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
*.gem
|
||||
*.rbc
|
||||
/.config
|
||||
/coverage/
|
||||
/InstalledFiles
|
||||
/pkg/
|
||||
/spec/reports/
|
||||
/spec/examples.txt
|
||||
/test/tmp/
|
||||
/test/version_tmp/
|
||||
/tmp/
|
||||
|
||||
# Used by dotenv library to load environment variables.
|
||||
# .env
|
||||
|
||||
# Ignore Byebug command history file.
|
||||
.byebug_history
|
||||
|
||||
## Specific to RubyMotion:
|
||||
.dat*
|
||||
.repl_history
|
||||
build/
|
||||
*.bridgesupport
|
||||
build-iPhoneOS/
|
||||
build-iPhoneSimulator/
|
||||
|
||||
## Specific to RubyMotion (use of CocoaPods):
|
||||
#
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||
#
|
||||
# vendor/Pods/
|
||||
|
||||
## Documentation cache and generated files:
|
||||
/.yardoc/
|
||||
/_yardoc/
|
||||
/doc/
|
||||
/rdoc/
|
||||
|
||||
## Environment normalization:
|
||||
/.bundle/
|
||||
/vendor/bundle
|
||||
/lib/bundler/man/
|
||||
|
||||
# for a library or gem, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# Gemfile.lock
|
||||
# .ruby-version
|
||||
# .ruby-gemset
|
||||
|
||||
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
||||
.rvmrc
|
||||
|
||||
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
||||
# .rubocop-https?--*
|
||||
|
||||
temp/
|
||||
output/
|
||||
license_key
|
||||
license_key.pub
|
||||
result.gitlab-license
|
||||
features.list
|
||||
.DS_Store
|
0
.root
Normal file
0
.root
Normal file
15
Dockerfile
Normal file
15
Dockerfile
Normal file
|
@ -0,0 +1,15 @@
|
|||
FROM ruby:bookworm
|
||||
WORKDIR /license-generator
|
||||
COPY ./ ./
|
||||
RUN <<EOF
|
||||
gem install gitlab-license
|
||||
EOF
|
||||
VOLUME /license-generator/build
|
||||
ENV LICENSE_NAME="Tim Cook"
|
||||
ENV LICENSE_COMPANY="Apple Computer, Inc."
|
||||
ENV LICENSE_EMAIL="tcook@apple.com"
|
||||
ENV LICENSE_PLAN="ultimate"
|
||||
ENV LICENSE_USER_COUNT="2147483647"
|
||||
ENV LICENSE_EXPIRE_YEAR="2500"
|
||||
|
||||
CMD [ "./make.sh" ]
|
13
LICENSE
Normal file
13
LICENSE
Normal file
|
@ -0,0 +1,13 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
208
README.md
Normal file
208
README.md
Normal file
|
@ -0,0 +1,208 @@
|
|||
<div align="center">
|
||||
|
||||
# GitLab License Generator
|
||||
|
||||
<p align="center">
|
||||
<a href="README.md">English</a> |
|
||||
<a href="lang/README_FR.md">Français</a> |
|
||||
<a href="lang/README_RU.md">Russian</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
**GitLab License Generator** This project generates a GitLab license for **development purposes**. If you encounter any problems, please troubleshoot them on your own.
|
||||
|
||||
> Last tested on GitLab v17.6.0-ee.
|
||||
|
||||
## Principles
|
||||
|
||||
### **src/generator.keys.rb**
|
||||
|
||||
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.
|
||||
|
||||
### **src/generator.license.rb**
|
||||
|
||||
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.
|
||||
|
||||
### **src/scan.features.rb**
|
||||
|
||||
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.
|
||||
|
||||
## Usage
|
||||
|
||||
### Using Docker image (Zero setup)
|
||||
|
||||
Using this method license files are generated under `./license` directory
|
||||
> Please note that in standard docker installations, owner of the files generated in license directory will be root
|
||||
|
||||
#### Method (1): Pull image
|
||||
|
||||
```bash
|
||||
docker run --rm -it \
|
||||
-v "./license:/license-generator/build" \
|
||||
-e LICENSE_NAME="Tim Cook" \
|
||||
-e LICENSE_COMPANY="Apple Computer, Inc." \
|
||||
-e LICENSE_EMAIL="tcook@apple.com" \
|
||||
-e LICENSE_PLAN="ultimate" \
|
||||
-e LICENSE_USER_COUNT="2147483647" \
|
||||
-e LICENSE_EXPIRE_YEAR="2500" \
|
||||
ghcr.io/lakr233/gitlab-license-generator:main
|
||||
```
|
||||
|
||||
#### Method (2): Build image
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Lakr233/GitLab-License-Generator.git
|
||||
docker build GitLab-License-Generator -t gitlab-license-generator:main
|
||||
docker run --rm -it \
|
||||
-v "./license:/license-generator/build" \
|
||||
-e LICENSE_NAME="Tim Cook" \
|
||||
-e LICENSE_COMPANY="Apple Computer, Inc." \
|
||||
-e LICENSE_EMAIL="tcook@apple.com" \
|
||||
-e LICENSE_PLAN="ultimate" \
|
||||
-e LICENSE_USER_COUNT="2147483647" \
|
||||
-e LICENSE_EXPIRE_YEAR="2500" \
|
||||
gitlab-license-generator:main
|
||||
```
|
||||
|
||||
### Manual: Prerequisites
|
||||
|
||||
Before starting, ensure your environment is properly configured.
|
||||
|
||||
#### 1. Install Ruby and gem
|
||||
|
||||
To run this project, you need **Ruby** and the **gem** package manager.
|
||||
|
||||
- **On Linux (Ubuntu/Debian)**:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install ruby-full
|
||||
```
|
||||
|
||||
- **On macOS** (via Homebrew):
|
||||
|
||||
```bash
|
||||
brew install ruby
|
||||
```
|
||||
|
||||
#### 2. Install Bundler and necessary gems
|
||||
|
||||
After installing Ruby, you need to install **Bundler** to manage Ruby dependencies.
|
||||
|
||||
```bash
|
||||
gem install bundler
|
||||
```
|
||||
|
||||
#### 3. Install the `gitlab-license` gem
|
||||
|
||||
The project requires the `gitlab-license` gem, which will be automatically downloaded and used by the script.
|
||||
|
||||
```bash
|
||||
gem install gitlab-license
|
||||
```
|
||||
|
||||
### Steps to Generate the GitLab License
|
||||
|
||||
#### 1. Clone the project repository
|
||||
|
||||
Clone this project to your local machine.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Lakr233/GitLab-License-Generator.git
|
||||
cd GitLab-License-Generator
|
||||
```
|
||||
|
||||
#### 2. Run the `make.sh` script
|
||||
|
||||
Once all the prerequisites are met, run the script:
|
||||
|
||||
```bash
|
||||
./make.sh
|
||||
```
|
||||
|
||||
The script will perform the following actions:
|
||||
|
||||
- Download and extract the `gitlab-license` gem.
|
||||
- Copy and modify the required files.
|
||||
- Clone the GitLab source code from GitLab.com.
|
||||
- Generate a public/private key pair.
|
||||
- Generate a GitLab license.
|
||||
|
||||
#### 3. Replace the public key in GitLab
|
||||
|
||||
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.
|
||||
|
||||
- **If GitLab is installed on your server**:
|
||||
|
||||
```bash
|
||||
sudo cp ./build/public.key /opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub
|
||||
sudo gitlab-ctl reconfigure
|
||||
sudo gitlab-ctl restart
|
||||
```
|
||||
|
||||
- **If GitLab is installed via Docker**:
|
||||
Modify your `docker-compose.yml` file to mount the new public key inside the container:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- "./build/public.key:/opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub"
|
||||
```
|
||||
|
||||
Then restart the container:
|
||||
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
#### 4. Install the license in GitLab
|
||||
|
||||
Once the public key is replaced, log in to GitLab’s admin interface to install the generated license.
|
||||
|
||||
1. Log in to GitLab as an administrator.
|
||||
2. Navigate to the **Admin Area** from the bottom-left corner.
|
||||
3. Go to **Settings > General** and upload the generated license file (`build/result.gitlab-license`).
|
||||
4. Check the **Terms of Service** checkbox and click **Add License**.
|
||||
|
||||
If necessary, you can directly access the license upload page via:
|
||||
|
||||
```
|
||||
<YourGitLabURL>/admin/license/new
|
||||
```
|
||||
|
||||
#### 5. Disable Service Ping (optional)
|
||||
|
||||
If you want to disable GitLab’s usage data collection (Service Ping), modify GitLab’s configuration file:
|
||||
|
||||
- Open the configuration file:
|
||||
|
||||
```bash
|
||||
sudo nano /etc/gitlab/gitlab.rb
|
||||
```
|
||||
|
||||
- Add the following line:
|
||||
|
||||
```bash
|
||||
gitlab_rails['usage_ping_enabled'] = false
|
||||
```
|
||||
|
||||
- Reconfigure and restart GitLab:
|
||||
|
||||
```bash
|
||||
sudo gitlab-ctl reconfigure
|
||||
sudo gitlab-ctl restart
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
- **HTTP 502 Error**:
|
||||
If you encounter this error, wait for GitLab to finish starting up (it may take some time).
|
||||
|
||||
## LICENSE
|
||||
|
||||
This project is licensed under the **WTFPL License**.
|
||||
|
||||
Copyright (c) 2023, Tim Cook, All Rights Not Reserved.
|
27
keys/private.key
Normal file
27
keys/private.key
Normal file
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAreEfP/ncA1A5cuxBz7rS0Z9DDxdSymLwt2OUSM5WJa+dVB3z
|
||||
SpQjinifdNZq+iHVt8toZBZZ02H3unbn8td0rIifoj4oVpLhvnOAVjUn5tZeUX17
|
||||
tWMA+yyBpf6w6IFxeYBXFd14WOKEarS05U9B59DjBxNqSm+GzhljHO7vvTKy2xXQ
|
||||
Q7Fa702DZ7jwr4DJnL87bDXfarnYksuawqtKwQbFHAOvxFj8ghBh1Gshap1abExD
|
||||
4l7QWxFMTCVOkLJmXiqfOi5KuMiaMsSUsCBNQDE3A5aKvpwLGozsvpGRMy5Tt4Sg
|
||||
HC7ZbgerBNe75olOoPDxZf7bBt0+O5A/UjK/HwIDAQABAoIBACb3f4hX112KugUu
|
||||
OyVxidNebKnSIUSn3ahLkayrSRUTASAbwi0he8GJfLqzXrAFqx6QYCml9KVxnBHW
|
||||
me6LKGOODrBOW73jFuIWgllPeky6F9MNWw7wTAT+GWP46u6AK8z93QZSZqkMwn4j
|
||||
VzLYiz2HS4mHaVebHMvNVq/iQCnW9ztZnsv9HSoFt2WY2Cm/9UpAtbqrWRQTVnCt
|
||||
F7E1M9KICUKyM13qOQe+d0sZWx6D8eKrFlPs4KDXATs2SuDsaWpmWj9G8alSeHEW
|
||||
Ut+2MsS5BYNIVaG0KqDFRKDyTkhXzevz98r5KylFqfAB2bCnaqIE0hdOXfYd+CR0
|
||||
wwRAQmECgYEA1CnEO0K+nU8tZUwdTkL3wvo6z2jEnA97Laay9D/fnAjd3q8niTyJ
|
||||
2DZQJp9omTa51/7EJw6YWhYdk078ZckwebWQPtXsA7MCTXSXL3+sGmL2GohDUovH
|
||||
G6zdn9sKws+U6tIOoEOMCLivEtmNM7HJXP3PViQr+rOUQV3ig/8v+s8CgYEA0c5c
|
||||
Or0Ta4apaM8aD6rP2Eilb3VC8AOvSzY36gN38ki/SwVH1ZTw/hbOYlQTsnk+OkXX
|
||||
205k9tc78+9GrcYSuupjqzEdZVRQSGSbT9qXMMYfM3wK2Z7i37Cehn4Qw4BOOlgR
|
||||
TvsvBd0FSnzVi2wAkhx0zL1hNUXHHAYnVdOxyrECgYEAwKbkb0NePw4ElLUW71fU
|
||||
DxKVkHz7+xH7sipq2WueqttKTMkTx4RXTyOSiF+75VRSURYgG68fHL50QK06d1rH
|
||||
T91UjBpIY9uKvbafChyOtK8j9lfBehU+yZyg6mVGUjuYZ9oyOcjcQZciMqWlmEla
|
||||
Jby7JudVoCKs/uY3p9BzSvUCgYAF7Pkn44033T7NqgPHa4ChUDPz+PDiDIiX7Dka
|
||||
D+0EV8+nU8fanXFNC+HaXxuLT+dVCAH3vLgXTK7xzdFGOTDwPIyCGkoFQaNe2BCW
|
||||
6cqZYw8giiFYUieAP+HKVKcujmInPbOHcoq6dKqglvQFExDVD56w5axoL8dW4Eme
|
||||
H/OGkQKBgHgQeK29Ntz7LcKlXYhQPkmYn+DWAmEq4J6XjjXyCV82HgEMmhIiAKKI
|
||||
UURKt4j6c7KSiAhnyITz9JeVRoAFVB3y/tSSc5E+CH3jG/G0YlToW20Itf6o8hwD
|
||||
XERkPPwsXVoZWR2FcUzcO7Bspm/JvkuaL+4u1fi+eNl7uF7RRaD1
|
||||
-----END RSA PRIVATE KEY-----
|
9
keys/public.key
Normal file
9
keys/public.key
Normal file
|
@ -0,0 +1,9 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAreEfP/ncA1A5cuxBz7rS
|
||||
0Z9DDxdSymLwt2OUSM5WJa+dVB3zSpQjinifdNZq+iHVt8toZBZZ02H3unbn8td0
|
||||
rIifoj4oVpLhvnOAVjUn5tZeUX17tWMA+yyBpf6w6IFxeYBXFd14WOKEarS05U9B
|
||||
59DjBxNqSm+GzhljHO7vvTKy2xXQQ7Fa702DZ7jwr4DJnL87bDXfarnYksuawqtK
|
||||
wQbFHAOvxFj8ghBh1Gshap1abExD4l7QWxFMTCVOkLJmXiqfOi5KuMiaMsSUsCBN
|
||||
QDE3A5aKvpwLGozsvpGRMy5Tt4SgHC7ZbgerBNe75olOoPDxZf7bBt0+O5A/UjK/
|
||||
HwIDAQAB
|
||||
-----END PUBLIC KEY-----
|
154
lang/README_FR.md
Normal file
154
lang/README_FR.md
Normal file
|
@ -0,0 +1,154 @@
|
|||
<div align="center">
|
||||
|
||||
# GitLab License Generator
|
||||
|
||||
<p align="center">
|
||||
<a href="../README.md">English</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
**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.
|
||||
|
||||
Dernier test effectué sur GitLab v17.5.1-ee.
|
||||
|
||||
## Principes
|
||||
|
||||
### **src/generator.keys.rb**
|
||||
|
||||
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.
|
||||
|
||||
### **src/generator.license.rb**
|
||||
|
||||
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.
|
||||
|
||||
### **src/scan.features.rb**
|
||||
|
||||
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.
|
||||
|
||||
## Utilisation
|
||||
|
||||
### Prérequis
|
||||
|
||||
Avant de commencer, assurez-vous que votre environnement est correctement configuré.
|
||||
|
||||
#### 1. Installer Ruby et gem
|
||||
Pour exécuter ce projet, vous devez installer **Ruby** et le gestionnaire de paquets **gem**.
|
||||
|
||||
- **Sous Linux (Ubuntu/Debian)** :
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install ruby-full
|
||||
```
|
||||
|
||||
- **Sous macOS** (via Homebrew) :
|
||||
```bash
|
||||
brew install ruby
|
||||
```
|
||||
|
||||
#### 2. Installer Bundler et les gems nécessaires
|
||||
Une fois Ruby installé, vous devez installer **Bundler** pour gérer les dépendances Ruby.
|
||||
|
||||
```bash
|
||||
gem install bundler
|
||||
```
|
||||
|
||||
#### 3. Installer le gem `gitlab-license`
|
||||
Le projet nécessite le gem `gitlab-license`, qui sera automatiquement téléchargé et utilisé par le script.
|
||||
|
||||
```bash
|
||||
gem install gitlab-license
|
||||
```
|
||||
|
||||
### Étapes pour générer la licence GitLab
|
||||
|
||||
#### 1. Cloner le dépôt du projet
|
||||
Clonez ce projet sur votre machine locale.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Lakr233/GitLab-License-Generator.git
|
||||
cd GitLab-License-Generator
|
||||
```
|
||||
|
||||
#### 2. Exécuter le script `make.sh`
|
||||
Une fois que tous les prérequis sont en place, exécutez le script :
|
||||
|
||||
```bash
|
||||
./make.sh
|
||||
```
|
||||
|
||||
Le script effectuera les actions suivantes :
|
||||
- Téléchargement et extraction du gem `gitlab-license`.
|
||||
- Copie et modification des fichiers nécessaires.
|
||||
- Clonage du code source GitLab depuis GitLab.com.
|
||||
- Génération d’une paire de clés publique/privée.
|
||||
- Génération d’une licence GitLab.
|
||||
|
||||
#### 3. Remplacer la clé publique dans GitLab
|
||||
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.
|
||||
|
||||
- **Si GitLab est installé sur votre serveur** :
|
||||
```bash
|
||||
sudo cp ./build/public.key /opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub
|
||||
sudo gitlab-ctl reconfigure
|
||||
sudo gitlab-ctl restart
|
||||
```
|
||||
|
||||
- **Si GitLab est installé via Docker** :
|
||||
Modifiez votre fichier `docker-compose.yml` pour monter la nouvelle clé publique dans le conteneur :
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- "./build/public.key:/opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub"
|
||||
```
|
||||
|
||||
Puis redémarrez le conteneur :
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
#### 4. Installer la licence dans GitLab
|
||||
Une fois la clé publique remplacée, connectez-vous à l'interface d'administration de GitLab pour installer la licence générée.
|
||||
|
||||
1. Connectez-vous à GitLab en tant qu’administrateur.
|
||||
2. Accédez à **Admin Area** via le coin supérieur droit.
|
||||
3. Allez dans **Settings > General** et téléchargez le fichier de licence généré (`build/result.gitlab-license`).
|
||||
4. Cochez la case **Terms of Service** et cliquez sur **Add License**.
|
||||
|
||||
Si nécessaire, accédez directement à la page de téléchargement de la licence via :
|
||||
```
|
||||
<YourGitLabURL>/admin/license/new
|
||||
```
|
||||
|
||||
#### 5. Désactiver Service Ping (optionnel)
|
||||
Si vous souhaitez désactiver la collecte de données d'utilisation par GitLab (Service Ping), modifiez le fichier de configuration GitLab :
|
||||
|
||||
- Ouvrez le fichier de configuration :
|
||||
```bash
|
||||
sudo nano /etc/gitlab/gitlab.rb
|
||||
```
|
||||
|
||||
- Ajoutez la ligne suivante :
|
||||
```bash
|
||||
gitlab_rails['usage_ping_enabled'] = false
|
||||
```
|
||||
|
||||
- Reconfigurez et redémarrez GitLab :
|
||||
```bash
|
||||
sudo gitlab-ctl reconfigure
|
||||
sudo gitlab-ctl restart
|
||||
```
|
||||
|
||||
### Résolution des problèmes
|
||||
|
||||
- **Erreur HTTP 502** :
|
||||
Si vous obtenez cette erreur, patientez simplement, car GitLab peut mettre du temps à démarrer.
|
||||
|
||||
## LICENCE
|
||||
|
||||
Ce projet est sous licence **WTFPL License**.
|
||||
|
||||
Copyright (c) 2023, Tim Cook, All Rights Not Reserved.
|
154
lang/README_RU.md
Normal file
154
lang/README_RU.md
Normal file
|
@ -0,0 +1,154 @@
|
|||
<div align="center">
|
||||
|
||||
# Генератор лицензий GitLab
|
||||
|
||||
<p align="center">
|
||||
<a href="../README.md">English</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
## Описание
|
||||
|
||||
**GitLab License Generator** Этот проект генерирует лицензию GitLab для **целей разработки**. Если у вас возникнут какие-либо проблемы, пожалуйста, устраните их самостоятельно.
|
||||
|
||||
> [Последнее тестирование](../README.md).
|
||||
|
||||
## Принципы
|
||||
|
||||
### **src/generator.keys.rb**
|
||||
|
||||
GitLab использует пару открытого/закрытого ключа для шифрования своей лицензии. Открытый ключ поставляется с дистрибутивом GitLab, а закрытый ключ хранится в безопасности. Сама лицензия представляет собой просто словарь JSON. Поскольку GitLab сделал свой код открытым, мы можем легко сгенерировать собственную лицензию.
|
||||
|
||||
### **src/generator.license.rb**
|
||||
|
||||
Папка `lib` извлекается из исходного кода GitLab. Она используется для сборки и проверки лицензии. Скрипт `src/generator.license.rb` загружает эту функциональность.
|
||||
|
||||
### **src/scan.features.rb**
|
||||
|
||||
Функции извлекаются из объекта, заполненного константами. Самый полный план лицензии — **Ultimate**, но такие функции, как Geo Mirroring, не включены ни в один стандартный план. Поэтому мы вручную добавляем эти функции.
|
||||
|
||||
## Использование
|
||||
|
||||
### Предпосылки
|
||||
|
||||
Перед началом убедитесь, что ваша среда правильно настроена.
|
||||
|
||||
#### 1. Установите Ruby и gem
|
||||
Для запуска этого проекта вам понадобится **Ruby** и менеджер пакетов **gem**.
|
||||
|
||||
- **В Linux (Ubuntu/Debian)**:
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install ruby-full
|
||||
```
|
||||
|
||||
- **На macOS** (через Homebrew):
|
||||
```bash
|
||||
brew install ruby
|
||||
```
|
||||
|
||||
#### 2. Установите Bundler и необходимые gems
|
||||
После установки Ruby вам необходимо установить **Bundler** для управления зависимостями Ruby.
|
||||
|
||||
```bash
|
||||
gem install bundler
|
||||
```
|
||||
|
||||
#### 3. Установите gem `gitlab-license`
|
||||
Для проекта требуется gem `gitlab-license`, который будет автоматически загружен и использован скриптом.
|
||||
|
||||
```bash
|
||||
gem install gitlab-license
|
||||
```
|
||||
|
||||
### Шаги по созданию лицензии GitLab
|
||||
|
||||
#### 1. Клонируйте репозиторий проекта
|
||||
Скопируйте этот проект на свой локальный компьютер.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Lakr233/GitLab-License-Generator.git
|
||||
cd GitLab-License-Generator
|
||||
```
|
||||
|
||||
#### 2. Запустите скрипт `make.sh`
|
||||
После выполнения всех предварительных условий запустите скрипт:
|
||||
|
||||
```bash
|
||||
./make.sh
|
||||
```
|
||||
|
||||
Скрипт выполнит следующие действия:
|
||||
- Загрузит и распакует gem-файл `gitlab-license`.
|
||||
- Скопирует и изменит необходимые файлы.
|
||||
- Клонирует исходный код GitLab с GitLab.com.
|
||||
- Сгенерирует пару открытого и закрытого ключей.
|
||||
- Создаст лицензию GitLab.
|
||||
|
||||
#### 3. Замена открытого ключа в GitLab
|
||||
Скрипт генерирует открытый ключ, расположенный в `build/public.key`. Вам необходимо заменить существующий открытый ключ GitLab на этот недавно сгенерированный, чтобы убедиться, что лицензия принята.
|
||||
|
||||
- **Если на вашем сервере установлен GitLab**:
|
||||
```bash
|
||||
sudo cp ./build/public.key /opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub
|
||||
sudo gitlab-ctl reconfigure
|
||||
sudo gitlab-ctl restart
|
||||
```
|
||||
|
||||
- **Если GitLab установлен через Docker**:
|
||||
Измените файл `docker-compose.yml`, чтобы смонтировать новый открытый ключ внутрь контейнера:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- "./build/public.key:/opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub"
|
||||
```
|
||||
|
||||
Затем перезапустите контейнер:
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
#### 4. Установите лицензию в GitLab
|
||||
После замены открытого ключа войдите в интерфейс администратора GitLab, чтобы установить сгенерированную лицензию.
|
||||
|
||||
1. Войдите в GitLab как администратор.
|
||||
2. Перейдите в **Admin Area** из верхнего правого угла.
|
||||
3. Перейдите в **Settings > General** и загрузите сгенерированный файл лицензии (`build/result.gitlab-license`).
|
||||
4. Установите флажок **Terms of Service** и нажмите **Add License**.
|
||||
|
||||
При необходимости вы можете напрямую перейти на страницу загрузки лицензии через:
|
||||
```
|
||||
<YourGitLabURL>/admin/license/new
|
||||
```
|
||||
|
||||
#### 5. Отключить Service Ping (необязательно)
|
||||
Если вы хотите отключить сбор данных об использовании GitLab (Service Ping), измените файл конфигурации GitLab:
|
||||
|
||||
- Откройте файл конфигурации:
|
||||
```bash
|
||||
sudo nano /etc/gitlab/gitlab.rb
|
||||
```
|
||||
|
||||
- Добавьте следующую строку:
|
||||
```bash
|
||||
gitlab_rails['usage_ping_enabled'] = false
|
||||
```
|
||||
|
||||
- Перенастройте и перезапустите GitLab:
|
||||
```bash
|
||||
sudo gitlab-ctl reconfigure
|
||||
sudo gitlab-ctl restart
|
||||
```
|
||||
|
||||
### Поиск неисправностей
|
||||
|
||||
- **Ошибка HTTP 502**:
|
||||
Если вы столкнулись с этой ошибкой, дождитесь завершения запуска GitLab (это может занять некоторое время).
|
||||
|
||||
## ЛИЦЕНЗИЯ
|
||||
|
||||
Данный проект лицензирован по **WTFPL License**.
|
||||
|
||||
Авторские права (c) 2023, Тим Кук, Все права не защищены.
|
309
lib/license.rb
Normal file
309
lib/license.rb
Normal file
|
@ -0,0 +1,309 @@
|
|||
require 'openssl'
|
||||
require 'date'
|
||||
require 'json'
|
||||
require 'base64'
|
||||
|
||||
require_relative 'license/version'
|
||||
require_relative 'license/encryptor'
|
||||
require_relative 'license/boundary'
|
||||
|
||||
module Gitlab
|
||||
class License
|
||||
class Error < StandardError; end
|
||||
class ImportError < Error; end
|
||||
class ValidationError < Error; end
|
||||
|
||||
class << self
|
||||
attr_reader :encryption_key
|
||||
attr_reader :fallback_decryption_keys
|
||||
@encryption_key = nil
|
||||
|
||||
def encryption_key=(key)
|
||||
raise ArgumentError, 'No RSA encryption key provided.' if key && !key.is_a?(OpenSSL::PKey::RSA)
|
||||
|
||||
@encryption_key = key
|
||||
@encryptor = nil
|
||||
end
|
||||
|
||||
def fallback_decryption_keys=(keys)
|
||||
unless keys
|
||||
@fallback_decryption_keys = nil
|
||||
return
|
||||
end
|
||||
|
||||
unless keys.is_a?(Enumerable) && keys.all? { |key| key.is_a?(OpenSSL::PKey::RSA) }
|
||||
raise ArgumentError, 'Invalid fallback RSA encryption keys provided.'
|
||||
end
|
||||
|
||||
@fallback_decryption_keys = Array(keys)
|
||||
end
|
||||
|
||||
def encryptor
|
||||
@encryptor ||= Encryptor.new(encryption_key)
|
||||
end
|
||||
|
||||
def import(data)
|
||||
raise ImportError, 'No license data.' if data.nil?
|
||||
|
||||
data = Boundary.remove_boundary(data)
|
||||
|
||||
license_json = decrypt_with_fallback_keys(data)
|
||||
|
||||
begin
|
||||
attributes = JSON.parse(license_json)
|
||||
rescue JSON::ParseError
|
||||
raise ImportError, 'License data is invalid JSON.'
|
||||
end
|
||||
|
||||
new(attributes)
|
||||
end
|
||||
|
||||
def decrypt_with_fallback_keys(data)
|
||||
keys_to_try = Array(encryption_key)
|
||||
keys_to_try += fallback_decryption_keys if fallback_decryption_keys
|
||||
|
||||
keys_to_try.each do |decryption_key|
|
||||
decryptor = Encryptor.new(decryption_key)
|
||||
return decryptor.decrypt(data)
|
||||
rescue Encryptor::Error
|
||||
next
|
||||
end
|
||||
|
||||
raise ImportError, 'License data could not be decrypted.'
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :version
|
||||
attr_accessor :licensee, :starts_at, :expires_at, :notify_admins_at,
|
||||
:notify_users_at, :block_changes_at, :last_synced_at, :next_sync_at,
|
||||
:activated_at, :restrictions, :cloud_licensing_enabled,
|
||||
:offline_cloud_licensing_enabled, :auto_renew_enabled, :seat_reconciliation_enabled,
|
||||
:operational_metrics_enabled, :generated_from_customers_dot,
|
||||
:generated_from_cancellation
|
||||
|
||||
alias_method :issued_at, :starts_at
|
||||
alias_method :issued_at=, :starts_at=
|
||||
|
||||
def initialize(attributes = {})
|
||||
load_attributes(attributes)
|
||||
end
|
||||
|
||||
def valid?
|
||||
if !licensee || !licensee.is_a?(Hash) || licensee.empty?
|
||||
false
|
||||
elsif !starts_at || !starts_at.is_a?(Date)
|
||||
false
|
||||
elsif !expires_at && !gl_team_license? && !jh_team_license?
|
||||
false
|
||||
elsif expires_at && !expires_at.is_a?(Date)
|
||||
false
|
||||
elsif notify_admins_at && !notify_admins_at.is_a?(Date)
|
||||
false
|
||||
elsif notify_users_at && !notify_users_at.is_a?(Date)
|
||||
false
|
||||
elsif block_changes_at && !block_changes_at.is_a?(Date)
|
||||
false
|
||||
elsif last_synced_at && !last_synced_at.is_a?(DateTime)
|
||||
false
|
||||
elsif next_sync_at && !next_sync_at.is_a?(DateTime)
|
||||
false
|
||||
elsif activated_at && !activated_at.is_a?(DateTime)
|
||||
false
|
||||
elsif restrictions && !restrictions.is_a?(Hash)
|
||||
false
|
||||
elsif !cloud_licensing? && offline_cloud_licensing?
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def validate!
|
||||
raise ValidationError, 'License is invalid' unless valid?
|
||||
end
|
||||
|
||||
def will_expire?
|
||||
expires_at
|
||||
end
|
||||
|
||||
def will_notify_admins?
|
||||
notify_admins_at
|
||||
end
|
||||
|
||||
def will_notify_users?
|
||||
notify_users_at
|
||||
end
|
||||
|
||||
def will_block_changes?
|
||||
block_changes_at
|
||||
end
|
||||
|
||||
def will_sync?
|
||||
next_sync_at
|
||||
end
|
||||
|
||||
def activated?
|
||||
activated_at
|
||||
end
|
||||
|
||||
def expired?
|
||||
will_expire? && Date.today >= expires_at
|
||||
end
|
||||
|
||||
def notify_admins?
|
||||
will_notify_admins? && Date.today >= notify_admins_at
|
||||
end
|
||||
|
||||
def notify_users?
|
||||
will_notify_users? && Date.today >= notify_users_at
|
||||
end
|
||||
|
||||
def block_changes?
|
||||
will_block_changes? && Date.today >= block_changes_at
|
||||
end
|
||||
|
||||
def cloud_licensing?
|
||||
cloud_licensing_enabled == true
|
||||
end
|
||||
|
||||
def offline_cloud_licensing?
|
||||
offline_cloud_licensing_enabled == true
|
||||
end
|
||||
|
||||
def auto_renew?
|
||||
auto_renew_enabled == true
|
||||
end
|
||||
|
||||
def seat_reconciliation?
|
||||
seat_reconciliation_enabled == true
|
||||
end
|
||||
|
||||
def operational_metrics?
|
||||
operational_metrics_enabled == true
|
||||
end
|
||||
|
||||
def generated_from_customers_dot?
|
||||
generated_from_customers_dot == true
|
||||
end
|
||||
|
||||
def generated_from_cancellation?
|
||||
generated_from_cancellation == true
|
||||
end
|
||||
|
||||
def gl_team_license?
|
||||
licensee['Company'].to_s.match?(/GitLab/i) && licensee['Email'].to_s.end_with?('@gitlab.com')
|
||||
end
|
||||
|
||||
def jh_team_license?
|
||||
licensee['Company'].to_s.match?(/GitLab/i) && licensee['Email'].to_s.end_with?('@jihulab.com')
|
||||
end
|
||||
|
||||
def restricted?(key = nil)
|
||||
if key
|
||||
restricted? && restrictions.has_key?(key)
|
||||
else
|
||||
restrictions && restrictions.length >= 1
|
||||
end
|
||||
end
|
||||
|
||||
def attributes
|
||||
hash = {}
|
||||
|
||||
hash['version'] = version
|
||||
hash['licensee'] = licensee
|
||||
|
||||
# `issued_at` is the legacy name for starts_at.
|
||||
# TODO: Move to starts_at in a next version.
|
||||
hash['issued_at'] = starts_at
|
||||
hash['expires_at'] = expires_at if will_expire?
|
||||
|
||||
hash['notify_admins_at'] = notify_admins_at if will_notify_admins?
|
||||
hash['notify_users_at'] = notify_users_at if will_notify_users?
|
||||
hash['block_changes_at'] = block_changes_at if will_block_changes?
|
||||
|
||||
hash['next_sync_at'] = next_sync_at if will_sync?
|
||||
hash['last_synced_at'] = last_synced_at if will_sync?
|
||||
hash['activated_at'] = activated_at if activated?
|
||||
|
||||
hash['cloud_licensing_enabled'] = cloud_licensing?
|
||||
hash['offline_cloud_licensing_enabled'] = offline_cloud_licensing?
|
||||
hash['auto_renew_enabled'] = auto_renew?
|
||||
hash['seat_reconciliation_enabled'] = seat_reconciliation?
|
||||
hash['operational_metrics_enabled'] = operational_metrics?
|
||||
|
||||
hash['generated_from_customers_dot'] = generated_from_customers_dot?
|
||||
hash['generated_from_cancellation'] = generated_from_cancellation?
|
||||
|
||||
hash['restrictions'] = restrictions if restricted?
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
def to_json(*_args)
|
||||
JSON.dump(attributes)
|
||||
end
|
||||
|
||||
def export(boundary: nil)
|
||||
validate!
|
||||
|
||||
data = self.class.encryptor.encrypt(to_json)
|
||||
|
||||
data = Boundary.add_boundary(data, boundary) if boundary
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_attributes(attributes)
|
||||
attributes = attributes.transform_keys(&:to_s)
|
||||
|
||||
version = attributes['version'] || 1
|
||||
raise ArgumentError, 'Version is too new' unless version && version == 1
|
||||
|
||||
@version = version
|
||||
|
||||
@licensee = attributes['licensee']
|
||||
|
||||
# `issued_at` is the legacy name for starts_at.
|
||||
# TODO: Move to starts_at in a next version.
|
||||
%w[issued_at expires_at notify_admins_at notify_users_at block_changes_at].each do |attr_name|
|
||||
set_date_attribute(attr_name, attributes[attr_name])
|
||||
end
|
||||
|
||||
%w[last_synced_at next_sync_at activated_at].each do |attr_name|
|
||||
set_datetime_attribute(attr_name, attributes[attr_name])
|
||||
end
|
||||
|
||||
%w[
|
||||
cloud_licensing_enabled
|
||||
offline_cloud_licensing_enabled
|
||||
auto_renew_enabled
|
||||
seat_reconciliation_enabled
|
||||
operational_metrics_enabled
|
||||
generated_from_customers_dot
|
||||
generated_from_cancellation
|
||||
].each do |attr_name|
|
||||
public_send("#{attr_name}=", attributes[attr_name] == true)
|
||||
end
|
||||
|
||||
restrictions = attributes['restrictions']
|
||||
if restrictions&.is_a?(Hash)
|
||||
restrictions = restrictions.transform_keys(&:to_sym)
|
||||
@restrictions = restrictions
|
||||
end
|
||||
end
|
||||
|
||||
def set_date_attribute(attr_name, value, date_class = Date)
|
||||
value = date_class.parse(value) rescue nil if value.is_a?(String)
|
||||
|
||||
return unless value
|
||||
|
||||
public_send("#{attr_name}=", value)
|
||||
end
|
||||
|
||||
def set_datetime_attribute(attr_name, value)
|
||||
set_date_attribute(attr_name, value, DateTime)
|
||||
end
|
||||
end
|
||||
end
|
40
lib/license/boundary.rb
Normal file
40
lib/license/boundary.rb
Normal file
|
@ -0,0 +1,40 @@
|
|||
module Gitlab
|
||||
class License
|
||||
module Boundary
|
||||
BOUNDARY_START = /(\A|\r?\n)-*BEGIN .+? LICENSE-*\r?\n/.freeze
|
||||
BOUNDARY_END = /\r?\n-*END .+? LICENSE-*(\r?\n|\z)/.freeze
|
||||
|
||||
class << self
|
||||
def add_boundary(data, product_name)
|
||||
data = remove_boundary(data)
|
||||
|
||||
product_name.upcase!
|
||||
|
||||
pad = lambda do |message, width|
|
||||
total_padding = [width - message.length, 0].max
|
||||
|
||||
padding = total_padding / 2.0
|
||||
[
|
||||
'-' * padding.ceil,
|
||||
message,
|
||||
'-' * padding.floor
|
||||
].join
|
||||
end
|
||||
|
||||
[
|
||||
pad.call("BEGIN #{product_name} LICENSE", 60),
|
||||
data.strip,
|
||||
pad.call("END #{product_name} LICENSE", 60)
|
||||
].join("\n")
|
||||
end
|
||||
|
||||
def remove_boundary(data)
|
||||
after_boundary = data.split(BOUNDARY_START).last
|
||||
in_boundary = after_boundary.split(BOUNDARY_END).first
|
||||
|
||||
in_boundary
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
92
lib/license/encryptor.rb
Normal file
92
lib/license/encryptor.rb
Normal file
|
@ -0,0 +1,92 @@
|
|||
module Gitlab
|
||||
class License
|
||||
class Encryptor
|
||||
class Error < StandardError; end
|
||||
class KeyError < Error; end
|
||||
class DecryptionError < Error; end
|
||||
|
||||
attr_accessor :key
|
||||
|
||||
def initialize(key)
|
||||
raise KeyError, 'No RSA encryption key provided.' if key && !key.is_a?(OpenSSL::PKey::RSA)
|
||||
|
||||
@key = key
|
||||
end
|
||||
|
||||
def encrypt(data)
|
||||
raise KeyError, 'Provided key is not a private key.' unless key.private?
|
||||
|
||||
# Encrypt the data using symmetric AES encryption.
|
||||
cipher = OpenSSL::Cipher::AES128.new(:CBC)
|
||||
cipher.encrypt
|
||||
aes_key = cipher.random_key
|
||||
aes_iv = cipher.random_iv
|
||||
|
||||
encrypted_data = cipher.update(data) + cipher.final
|
||||
|
||||
# Encrypt the AES key using asymmetric RSA encryption.
|
||||
encrypted_key = key.private_encrypt(aes_key)
|
||||
|
||||
encryption_data = {
|
||||
'data' => Base64.encode64(encrypted_data),
|
||||
'key' => Base64.encode64(encrypted_key),
|
||||
'iv' => Base64.encode64(aes_iv)
|
||||
}
|
||||
|
||||
json_data = JSON.dump(encryption_data)
|
||||
Base64.encode64(json_data)
|
||||
end
|
||||
|
||||
def decrypt(data)
|
||||
raise KeyError, 'Provided key is not a public key.' unless key.public?
|
||||
|
||||
json_data = Base64.decode64(data.chomp)
|
||||
|
||||
begin
|
||||
encryption_data = JSON.parse(json_data)
|
||||
rescue JSON::ParserError
|
||||
raise DecryptionError, 'Encryption data is invalid JSON.'
|
||||
end
|
||||
|
||||
unless %w[data key iv].all? { |key| encryption_data[key] }
|
||||
raise DecryptionError, 'Required field missing from encryption data.'
|
||||
end
|
||||
|
||||
encrypted_data = Base64.decode64(encryption_data['data'])
|
||||
encrypted_key = Base64.decode64(encryption_data['key'])
|
||||
aes_iv = Base64.decode64(encryption_data['iv'])
|
||||
|
||||
begin
|
||||
# Decrypt the AES key using asymmetric RSA encryption.
|
||||
aes_key = self.key.public_decrypt(encrypted_key)
|
||||
rescue OpenSSL::PKey::RSAError
|
||||
raise DecryptionError, 'AES encryption key could not be decrypted.'
|
||||
end
|
||||
|
||||
# Decrypt the data using symmetric AES encryption.
|
||||
cipher = OpenSSL::Cipher::AES128.new(:CBC)
|
||||
cipher.decrypt
|
||||
|
||||
begin
|
||||
cipher.key = aes_key
|
||||
rescue OpenSSL::Cipher::CipherError
|
||||
raise DecryptionError, 'AES encryption key is invalid.'
|
||||
end
|
||||
|
||||
begin
|
||||
cipher.iv = aes_iv
|
||||
rescue OpenSSL::Cipher::CipherError
|
||||
raise DecryptionError, 'AES IV is invalid.'
|
||||
end
|
||||
|
||||
begin
|
||||
data = cipher.update(encrypted_data) + cipher.final
|
||||
rescue OpenSSL::Cipher::CipherError
|
||||
raise DecryptionError, 'Data could not be decrypted.'
|
||||
end
|
||||
|
||||
data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
5
lib/license/version.rb
Normal file
5
lib/license/version.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
module Gitlab
|
||||
class License
|
||||
VERSION = '2.4.0'.freeze
|
||||
end
|
||||
end
|
126
make.sh
Normal file
126
make.sh
Normal file
|
@ -0,0 +1,126 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "[i] GitLab License Generator"
|
||||
echo "[i] Copyright (c) 2023 Tim Cook, All Rights Not Reserved"
|
||||
LICENSE_NAME="${LICENSE_NAME:-"Tim Cook"}"
|
||||
LICENSE_COMPANY="${LICENSE_COMPANY:-"Apple Computer, Inc."}"
|
||||
LICENSE_EMAIL="${LICENSE_EMAIL:-"tcook@apple.com"}"
|
||||
LICENSE_PLAN="${LICENSE_PLAN:-ultimate}"
|
||||
LICENSE_USER_COUNT="${LICENSE_USER_COUNT:-2147483647}"
|
||||
LICENSE_EXPIRE_YEAR="${LICENSE_EXPIRE_YEAR:-2500}"
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
if [ ! -f ".root" ]; then
|
||||
echo "[!] failed to locate project directory, aborting..."
|
||||
exit 1
|
||||
fi
|
||||
WORKING_DIR=$(pwd)
|
||||
|
||||
mkdir temp 2>/dev/null || true
|
||||
|
||||
echo "[*] fetching ruby gem version..."
|
||||
RB_GEM_NAME="gitlab-license"
|
||||
RB_GEM_LIST_OUTPUT=$(gem list --remote $RB_GEM_NAME)
|
||||
|
||||
RB_GEM_VERSION=""
|
||||
while IFS= read -r line; do
|
||||
if [[ $line == "gitlab-license ("* ]]; then
|
||||
RB_GEM_VERSION=${line#"gitlab-license ("}
|
||||
RB_GEM_VERSION=${RB_GEM_VERSION%")"}
|
||||
break
|
||||
fi
|
||||
done <<<"$RB_GEM_LIST_OUTPUT"
|
||||
|
||||
echo "[*] gitlab-license version: $RB_GEM_VERSION"
|
||||
RB_GEM_DOWNLOAD_URL="https://rubygems.org/downloads/gitlab-license-$RB_GEM_VERSION.gem"
|
||||
RB_GEM_DOWNLOAD_PATH=$(pwd)/temp/gem/gitlab-license.gem
|
||||
mkdir -p "$(dirname "$RB_GEM_DOWNLOAD_PATH")"
|
||||
curl -L "$RB_GEM_DOWNLOAD_URL" -o "$RB_GEM_DOWNLOAD_PATH" 1>/dev/null 2>/dev/null
|
||||
pushd "$(dirname "$RB_GEM_DOWNLOAD_PATH")" >/dev/null
|
||||
tar -xf gitlab-license.gem
|
||||
tar -xf data.tar.gz
|
||||
|
||||
if [ ! -f "./lib/gitlab/license.rb" ]; then
|
||||
echo "[!] failed to locate gem file, aborting..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[*] copying gem..."
|
||||
rm -rf "${WORKING_DIR:?}/lib" || true
|
||||
mkdir -p "$WORKING_DIR/lib"
|
||||
cp -r ./lib/gitlab/* "$WORKING_DIR/lib"
|
||||
popd >/dev/null
|
||||
|
||||
pushd lib >/dev/null
|
||||
echo "[*] patching lib requirements gem..."
|
||||
|
||||
# Determine the operating system
|
||||
OS_TYPE="$(uname -s)"
|
||||
|
||||
case "$OS_TYPE" in
|
||||
Linux*)
|
||||
sed_i_cmd="sed -i"
|
||||
;;
|
||||
Darwin*)
|
||||
sed_i_cmd="sed -i ''"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported OS: $OS_TYPE"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# replace `require 'gitlab/license/` with `require 'license/` to make it work
|
||||
find . -type f -exec $sed_i_cmd 's/require '\''gitlab\/license\//require_relative '\''license\//g' {} \;
|
||||
|
||||
popd >/dev/null
|
||||
|
||||
echo "[*] updated gem"
|
||||
|
||||
echo "[*] fetching gitlab source code..."
|
||||
GITLAB_SOURCE_CODE_DIR=$(pwd)/temp/src
|
||||
|
||||
mkdir -p "$GITLAB_SOURCE_CODE_DIR"
|
||||
echo "[*] downloading features file..."
|
||||
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"
|
||||
|
||||
BUILD_DIR=$(pwd)/build
|
||||
mkdir -p "$BUILD_DIR"
|
||||
|
||||
echo "[*] scanning features..."
|
||||
FEATURE_LIST_FILE=$BUILD_DIR/features.json
|
||||
rm -f "${FEATURE_LIST_FILE:?}" || true
|
||||
./src/scan.features.rb \
|
||||
-o "$FEATURE_LIST_FILE" \
|
||||
-f "$GITLAB_SOURCE_CODE_DIR/features.rb"
|
||||
|
||||
echo "[*] generating key pair..."
|
||||
PUBLIC_KEY_FILE=$BUILD_DIR/public.key
|
||||
PRIVATE_KEY_FILE=$BUILD_DIR/private.key
|
||||
cp -f ./keys/public.key "$PUBLIC_KEY_FILE"
|
||||
cp -f ./keys/private.key "$PRIVATE_KEY_FILE"
|
||||
|
||||
# execute following command to generate new keys
|
||||
# ./src/generator.keys.rb \
|
||||
# --public-key $PUBLIC_KEY_FILE \
|
||||
# --private-key $PRIVATE_KEY_FILE
|
||||
|
||||
echo "[*] generating license..."
|
||||
LICENSE_FILE=$BUILD_DIR/result.gitlab-license
|
||||
LICENSE_JSON_FILE=$BUILD_DIR/license.json
|
||||
|
||||
./src/generator.license.rb \
|
||||
-f "$FEATURE_LIST_FILE" \
|
||||
--public-key "$PUBLIC_KEY_FILE" \
|
||||
--private-key "$PRIVATE_KEY_FILE" \
|
||||
-o "$LICENSE_FILE" \
|
||||
--license-name "$LICENSE_NAME" \
|
||||
--license-company "$LICENSE_COMPANY" \
|
||||
--license-email "$LICENSE_EMAIL" \
|
||||
--license-plan "$LICENSE_PLAN" \
|
||||
--license-user-count "$LICENSE_USER_COUNT" \
|
||||
--license-expire-year "$LICENSE_EXPIRE_YEAR" \
|
||||
--plain-license "$LICENSE_JSON_FILE"
|
||||
|
||||
echo "[*] done $(basename "$0")"
|
44
src/generator.keys.rb
Normal file
44
src/generator.keys.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env ruby
|
||||
# encoding: utf-8
|
||||
|
||||
require 'optparse'
|
||||
require 'openssl'
|
||||
|
||||
public_key_file = nil
|
||||
private_key_file = nil
|
||||
|
||||
OptionParser.new do |opts|
|
||||
opts.banner = "Usage: generator.keys.rb [options]"
|
||||
|
||||
opts.on("--public-key PATH", "Specify public key file (required)") do |v|
|
||||
public_key_file = File.expand_path(v)
|
||||
end
|
||||
|
||||
opts.on("--private-key PATH", "Specify private key file (required)") do |v|
|
||||
private_key_file = File.expand_path(v)
|
||||
end
|
||||
|
||||
opts.on("-h", "--help", "Prints this help") do
|
||||
puts opts
|
||||
exit
|
||||
end
|
||||
end.parse!
|
||||
|
||||
if public_key_file.nil? || private_key_file.nil?
|
||||
puts "[!] missing required options"
|
||||
puts "[!] use -h for help"
|
||||
exit 1
|
||||
end
|
||||
|
||||
if File.exist?(private_key_file) || File.exist?(public_key_file)
|
||||
puts "[!] key pair already exists"
|
||||
puts "[!] remove them if you want to regenerate"
|
||||
exit 1
|
||||
end
|
||||
|
||||
puts "[*] generating rsa key pair..."
|
||||
key = OpenSSL::PKey::RSA.new(2048)
|
||||
File.write(private_key_file, key.to_pem)
|
||||
File.write(public_key_file, key.public_key.to_pem)
|
||||
|
||||
puts "[*] done"
|
180
src/generator.license.rb
Normal file
180
src/generator.license.rb
Normal file
|
@ -0,0 +1,180 @@
|
|||
#!/usr/bin/env ruby
|
||||
# encoding: utf-8
|
||||
|
||||
license_file_path = nil
|
||||
license_json_path = nil
|
||||
public_key_path = nil
|
||||
private_key_path = nil
|
||||
features_json_path = nil
|
||||
license_name="Tim Cook"
|
||||
license_company="Apple Computer, Inc."
|
||||
license_email="tcook@apple.com"
|
||||
license_plan='ultimate'
|
||||
license_user_count=2147483647
|
||||
license_expire_year=2500
|
||||
|
||||
require 'optparse'
|
||||
OptionParser.new do |opts|
|
||||
opts.banner = "Usage: generator.license.rb [options]"
|
||||
|
||||
opts.on("-o", "--output PATH", "Output to dir (required)") do |v|
|
||||
license_file_path = File.expand_path(v)
|
||||
end
|
||||
|
||||
opts.on("--public-key PATH", "Specify public key file (required)") do |v|
|
||||
public_key_path = File.expand_path(v)
|
||||
end
|
||||
|
||||
opts.on("--private-key PATH", "Specify private key file (required)") do |v|
|
||||
private_key_path = File.expand_path(v)
|
||||
end
|
||||
|
||||
opts.on("-f", "--features PATH", "Specify features json file (optional)") do |v|
|
||||
features_json_path = File.expand_path(v)
|
||||
end
|
||||
|
||||
opts.on("--plain-license PATH", "Export license in json if set, useful for debug. (optional)") do |v|
|
||||
license_json_path = File.expand_path(v)
|
||||
end
|
||||
|
||||
opts.on("--license-name NAME", "Specify license name (optional) [#{license_name}]") do |v|
|
||||
license_name = v
|
||||
end
|
||||
|
||||
opts.on("--license-company COMPANY", "Specify license company (optional) [#{license_company}]") do |v|
|
||||
license_company = v
|
||||
end
|
||||
|
||||
opts.on("--license-email EMAIL-ADDRESS", "Specify license email address (optional) [#{license_email}]") do |v|
|
||||
license_email = v
|
||||
end
|
||||
|
||||
opts.on("--license-plan PLAN", "Specify license plan (optional) [#{license_plan} (default), premium, starter]") do |v|
|
||||
license_plan = v
|
||||
end
|
||||
|
||||
opts.on("--license-user-count COUNT", "Specify license user count (optional) [#{license_user_count} (default)]") do |v|
|
||||
license_user_count = v.to_i
|
||||
end
|
||||
|
||||
opts.on("--license-expire-year YEAR", "Specify license expire year (optional) [#{license_expire_year} (default)]") do |v|
|
||||
license_expire_year = v.to_i
|
||||
end
|
||||
|
||||
opts.on("-h", "--help", "Prints this help") do
|
||||
puts opts
|
||||
exit
|
||||
end
|
||||
end
|
||||
.parse!
|
||||
|
||||
if license_file_path.nil? || public_key_path.nil? || private_key_path.nil?
|
||||
puts "[!] missing required options"
|
||||
puts "[!] use -h for help"
|
||||
exit 1
|
||||
end
|
||||
|
||||
if license_plan != 'ultimate' && license_plan != 'premium' && license_plan != 'starter'
|
||||
puts "[!] license plan is set to #{license_plan} which is not one of [ultimate, premium, starter]"
|
||||
puts "[!] use -h for help"
|
||||
exit 1
|
||||
end
|
||||
|
||||
if Time.now.year > license_expire_year
|
||||
puts "[!] license expiry year is set to #{license_expire_year} which is less than current year, this value must be greater than current year"
|
||||
puts "[!] use -h for help"
|
||||
exit 1
|
||||
end
|
||||
|
||||
if license_user_count < 1
|
||||
puts "[!] license user count is set to #{license_user_count} which is less minumum user count possible"
|
||||
puts "[!] use -h for help"
|
||||
exit 1
|
||||
end
|
||||
|
||||
# ==========
|
||||
|
||||
puts "[*] loading keys..."
|
||||
require 'openssl'
|
||||
PUBLIC_KEY = OpenSSL::PKey::RSA.new File.read(public_key_path)
|
||||
PRIVATE_KEY = OpenSSL::PKey::RSA.new File.read(private_key_path)
|
||||
|
||||
puts "[*] loading licenses..."
|
||||
require_relative '../lib/license.rb'
|
||||
puts "[i] lib gitlab-license: #{Gitlab::License::VERSION}"
|
||||
|
||||
if !features_json_path.nil?
|
||||
puts "[*] loading features from #{features_json_path}"
|
||||
require 'json'
|
||||
FEATURE_LIST = JSON.parse(File.read(features_json_path))
|
||||
else
|
||||
FEATURE_LIST = []
|
||||
end
|
||||
puts "[*] total features to inject: #{FEATURE_LIST.size}"
|
||||
|
||||
# ==========
|
||||
|
||||
puts "[*] building a license..."
|
||||
|
||||
Gitlab::License.encryption_key = PRIVATE_KEY
|
||||
|
||||
license = Gitlab::License.new
|
||||
|
||||
# don't use gitlab inc, search `gl_team_license` in lib for details
|
||||
license.licensee = {
|
||||
"Name" => license_name,
|
||||
"Company" => license_company,
|
||||
"Email" => license_email
|
||||
}
|
||||
|
||||
# required of course
|
||||
license.starts_at = Date.new(1976, 4, 1)
|
||||
puts Date.new()
|
||||
# required since gem gitlab-license v2.2.1
|
||||
license.expires_at = Date.new(license_expire_year, 4, 1)
|
||||
|
||||
# prevent gitlab crash at
|
||||
# notification_start_date = trial? ? expires_at - NOTIFICATION_DAYS_BEFORE_TRIAL_EXPIRY : block_changes_at
|
||||
license.block_changes_at = Date.new(license_expire_year, 4, 1)
|
||||
|
||||
# required
|
||||
license.restrictions = {
|
||||
plan: license_plan,
|
||||
# STARTER_PLAN = 'starter'
|
||||
# PREMIUM_PLAN = 'premium'
|
||||
# ULTIMATE_PLAN = 'ultimate'
|
||||
|
||||
active_user_count: license_user_count,
|
||||
# required, just dont overflow
|
||||
}
|
||||
|
||||
license.cloud_licensing_enabled = true
|
||||
license.offline_cloud_licensing_enabled = true
|
||||
|
||||
# restricted_attr will access restrictions
|
||||
# add_ons will access restricted_attr(:add_ons, {})
|
||||
# so here by we inject all features into restrictions
|
||||
# see scan.rb for a list of features that we are going to inject
|
||||
for feature in FEATURE_LIST
|
||||
license.restrictions[feature] = license_user_count
|
||||
end
|
||||
|
||||
puts "[*] validating license..."
|
||||
if !license.valid?
|
||||
puts "[E] license validation failed!"
|
||||
puts "[E] #{license.errors}"
|
||||
exit 1
|
||||
end
|
||||
puts "[*] license validated"
|
||||
|
||||
puts "[*] exporting license file..."
|
||||
|
||||
if !license_json_path.nil?
|
||||
puts "[*] writing to #{license_json_path}"
|
||||
File.write(license_json_path, JSON.pretty_generate(JSON.parse(license.to_json)))
|
||||
end
|
||||
|
||||
puts "[*] writing to #{license_file_path}"
|
||||
File.write(license_file_path, license.export)
|
||||
|
||||
puts "[*] done"
|
71
src/modify.license.rb
Normal file
71
src/modify.license.rb
Normal file
|
@ -0,0 +1,71 @@
|
|||
#!/usr/bin/env ruby
|
||||
# encoding: utf-8
|
||||
|
||||
require 'base64'
|
||||
require 'json'
|
||||
require 'openssl'
|
||||
require 'tempfile'
|
||||
require 'optparse'
|
||||
require_relative '../lib/license/encryptor'
|
||||
|
||||
public_key_path = nil
|
||||
in_file = nil
|
||||
|
||||
OptionParser.new do |opts|
|
||||
opts.banner = "Usage: xxx.rb [options]"
|
||||
|
||||
opts.on("-k", "--public-key PATH", "Specify public key file (required)") do |v|
|
||||
public_key_path = File.expand_path(v)
|
||||
end
|
||||
|
||||
opts.on("-i", "--in PATH", "input license path") do |v|
|
||||
in_file = File.expand_path(v)
|
||||
end
|
||||
|
||||
opts.on("-h", "--help", "Prints this help") do
|
||||
puts opts
|
||||
exit
|
||||
end
|
||||
end
|
||||
.parse!
|
||||
|
||||
if in_file.nil? || public_key_path.nil?
|
||||
puts "[!] missing required options"
|
||||
puts "[!] use -h for help"
|
||||
exit 1
|
||||
end
|
||||
|
||||
content = File.read(in_file)
|
||||
attributes = JSON.parse(Base64.decode64(content))
|
||||
|
||||
PUBLIC_KEY = OpenSSL::PKey::RSA.new File.read(public_key_path)
|
||||
decryptor = Gitlab::License::Encryptor.new(PUBLIC_KEY)
|
||||
plain_license = decryptor.decrypt(content)
|
||||
edited_json = nil
|
||||
|
||||
Tempfile.create(['json_edit', '.json']) do |file|
|
||||
file.write(JSON.pretty_generate(JSON.parse(plain_license)))
|
||||
file.flush
|
||||
|
||||
system("vim #{file.path}")
|
||||
file.rewind
|
||||
edited_json = file.read
|
||||
end
|
||||
|
||||
edited_json = JSON.generate(JSON.parse(edited_json))
|
||||
|
||||
cipher = OpenSSL::Cipher::AES128.new(:CBC)
|
||||
cipher.encrypt
|
||||
cipher.key = PUBLIC_KEY.public_decrypt(Base64.decode64(attributes['key']))
|
||||
cipher.iv = Base64.decode64(attributes['iv'])
|
||||
|
||||
encrypted_data = cipher.update(edited_json) + cipher.final
|
||||
|
||||
encryption_data = {
|
||||
'data' => Base64.encode64(encrypted_data),
|
||||
'key' => attributes['key'],
|
||||
'iv' => attributes['iv']
|
||||
}
|
||||
|
||||
json_data = JSON.dump(encryption_data)
|
||||
puts Base64.encode64(json_data)
|
Loading…
Reference in a new issue