mirror of
https://github.com/Lakr233/GitLab-License-Generator.git
synced 2026-01-30 03:45:36 +02:00
Auto Update
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -54,3 +54,10 @@ build-iPhoneSimulator/
|
||||
|
||||
# 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
|
||||
|
||||
49
feature.scan.py
Executable file
49
feature.scan.py
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
|
||||
SCANNING_DIR = sys.argv[1]
|
||||
OUTPUT_LIST_FILE = sys.argv[2]
|
||||
print(f"[*] scanning directory: {SCANNING_DIR}")
|
||||
|
||||
# use regex to find the string
|
||||
# eg ::License.feature_available?(:aaa) || ::Feature.enabled?(:bbb, self)
|
||||
# make sure +? for shortest match
|
||||
REGEX_PARTTERN = "License.feature_available\?\(:.+?\)"
|
||||
|
||||
REQUIRED_FILE_SUFFIX = ['rb']
|
||||
|
||||
scanning_file_list = set()
|
||||
def build_file_list(input: str):
|
||||
global scanning_file_list
|
||||
scanning_file_list.add(input)
|
||||
if os.path.isdir(input):
|
||||
for file in os.listdir(input):
|
||||
build_file_list(os.path.join(input, file))
|
||||
build_file_list(SCANNING_DIR)
|
||||
|
||||
print(f"[*] scanning {len(scanning_file_list)} files...")
|
||||
feature_list=set()
|
||||
for file in scanning_file_list:
|
||||
if not os.path.isfile(file): continue
|
||||
if not file.split(".")[-1] in REQUIRED_FILE_SUFFIX: continue
|
||||
with open(file, "r") as f:
|
||||
content = f.read()
|
||||
all_match = re.findall(REGEX_PARTTERN, content)
|
||||
all_match = [x.split(":")[1].split(")")[0] for x in all_match]
|
||||
all_match = [x for x in all_match if x]
|
||||
feature_list.update(all_match)
|
||||
print(f"[*] found {len(feature_list)} features")
|
||||
|
||||
feature_list = list(feature_list)
|
||||
feature_list.sort()
|
||||
|
||||
print(f"[*] writing to {OUTPUT_LIST_FILE}...")
|
||||
with open(OUTPUT_LIST_FILE, "w") as f:
|
||||
for feature in feature_list:
|
||||
f.write(feature + "\n")
|
||||
|
||||
print(f"[*] done")
|
||||
@@ -1,31 +1,47 @@
|
||||
# GitLab License Generator
|
||||
#!/usr/bin/env ruby
|
||||
# encoding: utf-8
|
||||
|
||||
require 'openssl'
|
||||
require_relative 'lib/license.rb'
|
||||
puts "[i] lib gitlab-license: #{Gitlab::License::VERSION}"
|
||||
|
||||
OUTPUT_DIR = ARGV[0]
|
||||
puts "[*] output dir: #{OUTPUT_DIR}"
|
||||
|
||||
LICENSE_TARGET_PRIVATE_KEY = "license_key"
|
||||
LICENSE_TARGET_PUBLIC_KEY = "license_key.pub"
|
||||
TARGET_LICENSE_FILE = 'result.gitlab-license'
|
||||
TARGET_PLAIN_LICENSE_FILE = 'result.gitlab-license.json'
|
||||
|
||||
puts "[*] Booting generator"
|
||||
FEATURE_LIST = []
|
||||
if ARGV[1].nil?
|
||||
puts "[i] you can provide a list of feature to be enabled inside license"
|
||||
else
|
||||
FEATURE_LIST_FILE = ARGV[1]
|
||||
File.open(FEATURE_LIST_FILE).each do |line|
|
||||
FEATURE_LIST.push(line.chomp)
|
||||
end
|
||||
FEATURE_LIST.uniq!
|
||||
end
|
||||
puts "[*] loaded #{FEATURE_LIST.length} features"
|
||||
|
||||
require 'openssl'
|
||||
|
||||
require_relative 'lib/license.rb'
|
||||
CORE_LIB_VERSION = '2.2.1'
|
||||
|
||||
puts "[i] Using core library version #{CORE_LIB_VERSION}"
|
||||
Dir.chdir(OUTPUT_DIR)
|
||||
puts "[*] switching working dir: #{Dir.pwd}"
|
||||
|
||||
puts "[*] generating license..."
|
||||
if !File.exist?(LICENSE_TARGET_PRIVATE_KEY) || !File.exist?(LICENSE_TARGET_PUBLIC_KEY)
|
||||
puts "[*] Generating RSA keys..."
|
||||
puts "[*] generating rsa key pair..."
|
||||
key = OpenSSL::PKey::RSA.new(2048)
|
||||
File.write(LICENSE_TARGET_PRIVATE_KEY, key.to_pem)
|
||||
File.write(LICENSE_TARGET_PUBLIC_KEY, key.public_key.to_pem)
|
||||
end
|
||||
|
||||
puts "[*] Loading RSA keys..."
|
||||
puts "[*] loading key pair..."
|
||||
|
||||
public_key = OpenSSL::PKey::RSA.new File.read(LICENSE_TARGET_PUBLIC_KEY)
|
||||
private_key = OpenSSL::PKey::RSA.new File.read(LICENSE_TARGET_PRIVATE_KEY)
|
||||
|
||||
puts "[*] Building license..."
|
||||
puts "[*] building license..."
|
||||
|
||||
Gitlab::License.encryption_key = private_key
|
||||
|
||||
@@ -59,20 +75,17 @@ license.restrictions = {
|
||||
# required, just dont overflow
|
||||
}
|
||||
|
||||
puts "[*] Calling export..."
|
||||
if !license.valid?
|
||||
puts "[E] license validation failed!"
|
||||
puts "[E] #{license.errors}"
|
||||
exit 1
|
||||
end
|
||||
|
||||
puts ""
|
||||
puts "====================================================="
|
||||
puts "[*] exporting license file..."
|
||||
|
||||
puts JSON.pretty_generate(JSON.parse(license.to_json))
|
||||
|
||||
puts "====================================================="
|
||||
File.open(TARGET_PLAIN_LICENSE_FILE, "w") { |f| f.write(JSON.pretty_generate(JSON.parse(license.to_json))) }
|
||||
|
||||
data = license.export
|
||||
File.open(TARGET_LICENSE_FILE, "w") { |f| f.write(data) }
|
||||
|
||||
puts "====================================================="
|
||||
puts ""
|
||||
|
||||
puts "[*] License generated successfully!"
|
||||
puts "[*] License file: #{TARGET_LICENSE_FILE}"
|
||||
puts "[*] done"
|
||||
|
||||
@@ -15,6 +15,7 @@ module Gitlab
|
||||
|
||||
class << self
|
||||
attr_reader :encryption_key
|
||||
attr_reader :fallback_decryption_keys
|
||||
@encryption_key = nil
|
||||
|
||||
def encryption_key=(key)
|
||||
@@ -24,6 +25,19 @@ module Gitlab
|
||||
@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
|
||||
@@ -33,11 +47,7 @@ module Gitlab
|
||||
|
||||
data = Boundary.remove_boundary(data)
|
||||
|
||||
begin
|
||||
license_json = encryptor.decrypt(data)
|
||||
rescue Encryptor::Error
|
||||
raise ImportError, 'License data could not be decrypted.'
|
||||
end
|
||||
license_json = decrypt_with_fallback_keys(data)
|
||||
|
||||
begin
|
||||
attributes = JSON.parse(license_json)
|
||||
@@ -47,6 +57,20 @@ module Gitlab
|
||||
|
||||
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
|
||||
@@ -54,7 +78,8 @@ module Gitlab
|
||||
: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
|
||||
:operational_metrics_enabled, :generated_from_customers_dot,
|
||||
:generated_from_cancellation
|
||||
|
||||
alias_method :issued_at, :starts_at
|
||||
alias_method :issued_at=, :starts_at=
|
||||
@@ -65,43 +90,30 @@ module Gitlab
|
||||
|
||||
def valid?
|
||||
if !licensee || !licensee.is_a?(Hash) || licensee.empty?
|
||||
puts "Invalid License - licensee is not a hash or is empty"
|
||||
false
|
||||
elsif !starts_at || !starts_at.is_a?(Date)
|
||||
puts "Invalid License - starts_at is not a date"
|
||||
false
|
||||
elsif !expires_at && !gl_team_license? && !jh_team_license?
|
||||
puts "Invalid License - expires_at is not a date"
|
||||
false
|
||||
elsif expires_at && !expires_at.is_a?(Date)
|
||||
puts "Invalid License - expires_at is not a date"
|
||||
false
|
||||
elsif notify_admins_at && !notify_admins_at.is_a?(Date)
|
||||
puts "Invalid License - notify_admins_at is not a date"
|
||||
false
|
||||
elsif notify_users_at && !notify_users_at.is_a?(Date)
|
||||
puts "Invalid License - notify_users_at is not a date"
|
||||
false
|
||||
elsif block_changes_at && !block_changes_at.is_a?(Date)
|
||||
puts "Invalid License - block_changes_at is not a date"
|
||||
false
|
||||
elsif last_synced_at && !last_synced_at.is_a?(DateTime)
|
||||
puts "Invalid License - last_synced_at is not a datetime"
|
||||
false
|
||||
elsif next_sync_at && !next_sync_at.is_a?(DateTime)
|
||||
puts "Invalid License - next_sync_at is not a datetime"
|
||||
false
|
||||
elsif activated_at && !activated_at.is_a?(DateTime)
|
||||
puts "Invalid License - activated_at is not a datetime"
|
||||
false
|
||||
elsif restrictions && !restrictions.is_a?(Hash)
|
||||
puts "Invalid License - restrictions is not a hash"
|
||||
false
|
||||
elsif !cloud_licensing? && offline_cloud_licensing?
|
||||
puts "Invalid License - offline_cloud_licensing_enabled is true but cloud_licensing_enabled is false"
|
||||
false
|
||||
else
|
||||
puts "License is valid"
|
||||
true
|
||||
end
|
||||
end
|
||||
@@ -174,6 +186,10 @@ module Gitlab
|
||||
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
|
||||
@@ -216,6 +232,7 @@ module Gitlab
|
||||
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?
|
||||
|
||||
@@ -265,6 +282,7 @@ module Gitlab
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module Gitlab
|
||||
class License
|
||||
VERSION = '2.2.1'.freeze
|
||||
VERSION = '2.4.0'.freeze
|
||||
end
|
||||
end
|
||||
|
||||
27
license_key
27
license_key
@@ -1,27 +0,0 @@
|
||||
-----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-----
|
||||
@@ -1,9 +0,0 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAreEfP/ncA1A5cuxBz7rS
|
||||
0Z9DDxdSymLwt2OUSM5WJa+dVB3zSpQjinifdNZq+iHVt8toZBZZ02H3unbn8td0
|
||||
rIifoj4oVpLhvnOAVjUn5tZeUX17tWMA+yyBpf6w6IFxeYBXFd14WOKEarS05U9B
|
||||
59DjBxNqSm+GzhljHO7vvTKy2xXQQ7Fa702DZ7jwr4DJnL87bDXfarnYksuawqtK
|
||||
wQbFHAOvxFj8ghBh1Gshap1abExD4l7QWxFMTCVOkLJmXiqfOi5KuMiaMsSUsCBN
|
||||
QDE3A5aKvpwLGozsvpGRMy5Tt4SgHC7ZbgerBNe75olOoPDxZf7bBt0+O5A/UjK/
|
||||
HwIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
83
make.sh
83
make.sh
@@ -1,4 +1,81 @@
|
||||
#!/bin/bash
|
||||
#!/bin/zsh
|
||||
|
||||
cd "$(dirname "$0")" || exit 1
|
||||
ruby ./generate_licenses.rb
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
if [ ! -f ".root" ]; then
|
||||
echo "[!] failed to locate project directory, aborting..."
|
||||
exit 1
|
||||
fi
|
||||
WORKING_DIR=$(pwd)
|
||||
|
||||
mkdir temp || 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
|
||||
pushd $(dirname $RB_GEM_DOWNLOAD_PATH) > /dev/null
|
||||
tar -xzf gitlab-license.gem
|
||||
tar -xzf 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..."
|
||||
# replace `require 'gitlab/license/` with `require 'license/` to make it work
|
||||
find . -type f -exec sed -i '' '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/
|
||||
if [ -d "$GITLAB_SOURCE_CODE_DIR" ]; then
|
||||
echo "[*] gitlab source code already exists, skipping cloning..."
|
||||
else
|
||||
echo "[*] cloning gitlab source code..."
|
||||
git clone https://gitlab.com/gitlab-org/gitlab.git $GITLAB_SOURCE_CODE_DIR
|
||||
fi
|
||||
|
||||
echo "[*] updating gitlab source code..."
|
||||
pushd $GITLAB_SOURCE_CODE_DIR > /dev/null
|
||||
git clean -fdx -f
|
||||
git reset --hard
|
||||
git pull
|
||||
popd > /dev/null
|
||||
|
||||
echo "[*] scanning features..."
|
||||
FEATURE_LIST_FILE=$(pwd)/temp/features.txt
|
||||
rm -f $FEATURE_LIST_FILE || true
|
||||
./feature.scan.py $GITLAB_SOURCE_CODE_DIR $FEATURE_LIST_FILE
|
||||
|
||||
echo "[*] generating license..."
|
||||
OUTPUT_DIR=$(pwd)/output
|
||||
mkdir -p $OUTPUT_DIR
|
||||
ruby ./generate_licenses.rb $OUTPUT_DIR $FEATURE_LIST_FILE
|
||||
|
||||
echo "[*] done $(basename $0)"
|
||||
@@ -1,24 +0,0 @@
|
||||
eyJkYXRhIjoiOW5mNE9BaTBjYmxMendXbks4TGdDOWpDeVpNM1QzYzBNdzNs
|
||||
WS94WGlVR1o3UG9kNDNtWGlmSzJYcDNIXG5pWlc2UEhtVld0VFVUY3RabjF2
|
||||
Rk9wWXliZm1XUjM5dkxSQVhkVzJmcFBCQjd2eWwvY3kzaWF5dEdCZkxcblIx
|
||||
NWk4bmcvRlBpZ1Q2bXI1aFhoT1VKZm9xSHJ5RkE3NXV1b01IQkI0WHI4RGhl
|
||||
WVpsTEt6RmJueEZJdlxuRVkxZDk0Umd4d0dxcitqSDg0ZWMwKzhWcDFYaFEy
|
||||
NmhJWnpWMXRXWjY1Q2VVYVJ5TzJ2c2loeGhuRWRzXG5iOTVYWTZVaVJ6TlZs
|
||||
Ty8xaHByY3A1eklBVzBJQ0lwM2c3anR2SEtCWExuUkxnUDJucTN0UkhWNXM5
|
||||
T2dcbllmVkhseUZqZjRvclFpeGc1TEFVZmcwR0R6N0pDck9oc0xtWUZxTXQw
|
||||
SkZkamQ5YlhGU21OdzhkN2x4M1xuWU12MitXbS9zZ1ZiQzVFa1VJWExSaHlH
|
||||
bThjRjZNbEoya3N3MCttREVlNDFCem1ncHVWWWpyT01DQlJFXG56My9DSWRV
|
||||
dnFqY0ljTFFYYUdFajRTNmJtdjVxTXhYQTZiR3Bkd2orTVM4Y0doYjhGVENS
|
||||
UWVsRVlSVGVcbnZ1Z3lJdnZ6V2dYQWtCZk5NTU9Rd2JmMHFmOVJNK3FyN2lQ
|
||||
VXkxRWlYU2hDaHloTDhnV3BNc1FvVVNUNVxuSHZDcEE1Y2dPUmV1dC9YS1RH
|
||||
OHRIMFRJR2RmNjRDd3pFeENQKzN4QWJmM3IrSDJrZlhzaTFJWVhya25CXG5u
|
||||
aFhGTm83Q1doNUFJVWd1SmdnPVxuIiwia2V5IjoiT3huRG1YTEozcXVOZita
|
||||
K2lvU3RQMm5wa2U2K2ZMNVBpdEtJSkNkTUhNeTlHTmdhTVNoNnZlbERaUExz
|
||||
XG5JK3dJaHlEZ09vc2k0OEM4Tmp6Q29oL05mV3gybDJGRmxRSkFQLytRdGd4
|
||||
eDJiRnpFRlF5bk0zc0dnRUtcbkZRUkQzUGNTWkpzZGtXdkltWGEzWnlsMEg2
|
||||
WEtGelgrTnE0cGhqWktuQ1dneXk3dGU4YWI5Qm5ZNVBlYVxuWUNPL1I0SGpI
|
||||
MkhKTnhmamd2TWh0YThMNXgrbmt2RXhBODFIRDFsQlVXZzJlQi92RzZjblg0
|
||||
YkRPRWF3XG5tVHJpMS9VLzRVcVVoQnRSYklVSnZZeGFCMC9hT3owaStLVkdw
|
||||
SENSTCs3OXQveHA1NVg2bkRQWlhwdGdcbkE0WXJrbFVHUlF0RnZyMjRRMGxa
|
||||
TndrS2Z4eU1pOWkrclgrVzVIa1MvQT09XG4iLCJpdiI6Im1FL1RodjE4MWJQ
|
||||
eGNFaWVwdEhCWnc9PVxuIn0=
|
||||
Reference in New Issue
Block a user