diff --git a/.github/workflows/bake_to_latest.yml b/.github/workflows/bake_to_latest.yml index 0d5c8c6..73a8c25 100644 --- a/.github/workflows/bake_to_latest.yml +++ b/.github/workflows/bake_to_latest.yml @@ -14,38 +14,43 @@ jobs: contents: read steps: - name: Checkout - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v5 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 with: platforms: all - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1.6.0 + uses: docker/setup-buildx-action@v3 + - name: Login to DockerHub + uses: docker/login-action@v1.10.0 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} - name: Login to GitHub Container Registry uses: docker/login-action@v1.10.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build - uses: docker/build-push-action@v2 + - name: Build (full) + uses: docker/build-push-action@v6 with: context: . file: ./docker/docker-py3-kms/Dockerfile platforms: linux/amd64,linux/386,linux/arm64/v8,linux/arm/v7,linux/arm/v6 push: true - tags: ghcr.io/py-kms-organization/py-kms:python3 + tags: pykmsorg/py-kms:python3,ghcr.io/py-kms-organization/py-kms:python3 build-args: | BUILD_COMMIT=${{ github.sha }} BUILD_BRANCH=${{ github.ref_name }} - - name: Build - uses: docker/build-push-action@v2 + - name: Build (minimal) + uses: docker/build-push-action@v6 with: context: . file: ./docker/docker-py3-kms-minimal/Dockerfile platforms: linux/amd64,linux/386,linux/arm64/v8,linux/arm/v7,linux/arm/v6 push: true - tags: ghcr.io/py-kms-organization/py-kms:latest,ghcr.io/py-kms-organization/py-kms:minimal + tags: pykmsorg/py-kms:latest,ghcr.io/py-kms-organization/py-kms:latest,pykmsorg/py-kms:minimal,ghcr.io/py-kms-organization/py-kms:minimal build-args: | BUILD_COMMIT=${{ github.sha }} BUILD_BRANCH=${{ github.ref_name }} diff --git a/.github/workflows/bake_to_next.yml b/.github/workflows/bake_to_next.yml index 5fc1b6c..99032e0 100644 --- a/.github/workflows/bake_to_next.yml +++ b/.github/workflows/bake_to_next.yml @@ -14,38 +14,43 @@ jobs: contents: read steps: - name: Checkout - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v5 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 with: platforms: all - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1.6.0 + uses: docker/setup-buildx-action@v3 + - name: Login to DockerHub + uses: docker/login-action@v1.10.0 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} - name: Login to GitHub Container Registry uses: docker/login-action@v1.10.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build - uses: docker/build-push-action@v2 + - name: Build (full) + uses: docker/build-push-action@v6 with: context: . file: ./docker/docker-py3-kms/Dockerfile platforms: linux/amd64,linux/386,linux/arm64/v8,linux/arm/v7,linux/arm/v6 push: true - tags: ghcr.io/py-kms-organization/py-kms:python3-next + tags: pykmsorg/py-kms:python3-next,ghcr.io/py-kms-organization/py-kms:python3-next build-args: | BUILD_COMMIT=${{ github.sha }} BUILD_BRANCH=${{ github.ref_name }} - - name: Build - uses: docker/build-push-action@v2 + - name: Build (minimal) + uses: docker/build-push-action@v6 with: context: . file: ./docker/docker-py3-kms-minimal/Dockerfile platforms: linux/amd64,linux/386,linux/arm64/v8,linux/arm/v7,linux/arm/v6 push: true - tags: ghcr.io/py-kms-organization/py-kms:latest-next,ghcr.io/py-kms-organization/py-kms:minimal-next + tags: pykmsorg/py-kms:latest-next,ghcr.io/py-kms-organization/py-kms:latest-next,pykmsorg/py-kms:minimal-next,ghcr.io/py-kms-organization/py-kms:minimal-next build-args: | BUILD_COMMIT=${{ github.sha }} BUILD_BRANCH=${{ github.ref_name }} diff --git a/.github/workflows/bake_to_test.yml b/.github/workflows/bake_to_test.yml index 2790ba4..72fc196 100644 --- a/.github/workflows/bake_to_test.yml +++ b/.github/workflows/bake_to_test.yml @@ -9,15 +9,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v5 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 with: platforms: all - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1.6.0 - - name: Build - uses: docker/build-push-action@v2 + uses: docker/setup-buildx-action@v3 + - name: Build (full) + uses: docker/build-push-action@v6 with: context: . file: ./docker/docker-py3-kms/Dockerfile @@ -26,8 +26,8 @@ jobs: build-args: | BUILD_COMMIT=${{ github.sha }} BUILD_BRANCH=${{ github.ref_name }} - - name: Build - uses: docker/build-push-action@v2 + - name: Build (minimal) + uses: docker/build-push-action@v6 with: context: . file: ./docker/docker-py3-kms-minimal/Dockerfile @@ -35,4 +35,4 @@ jobs: push: false build-args: | BUILD_COMMIT=${{ github.sha }} - BUILD_BRANCH=${{ github.ref_name }} \ No newline at end of file + BUILD_BRANCH=${{ github.ref_name }} diff --git a/.readthedocs.yaml b/.readthedocs.yaml index e962b25..51107d5 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,12 +1,15 @@ version: 2 build: - os: "ubuntu-22.04" + os: "ubuntu-24.04" tools: - python: "3.10" + python: "3.12" python: install: - requirements: docs/requirements.txt +sphinx: + configuration: docs/conf.py + formats: all diff --git a/README.md b/README.md index 0ba649e..8eb8138 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ![repo-size](https://img.shields.io/github/repo-size/Py-KMS-Organization/py-kms) ![open-issues](https://img.shields.io/github/issues/Py-KMS-Organization/py-kms) ![last-commit](https://img.shields.io/github/last-commit/Py-KMS-Organization/py-kms/master) +![docker-pulls](https://img.shields.io/docker/pulls/pykmsorg/py-kms) ![read-the-docs](https://img.shields.io/readthedocs/py-kms) *** diff --git a/docker/docker-py3-kms-minimal/Dockerfile b/docker/docker-py3-kms-minimal/Dockerfile index a2d0df9..1807b37 100644 --- a/docker/docker-py3-kms-minimal/Dockerfile +++ b/docker/docker-py3-kms-minimal/Dockerfile @@ -1,19 +1,19 @@ # This is a minimized version from docker/docker-py3-kms/Dockerfile without SQLite support to further reduce image size -FROM alpine:3.15 +FROM alpine:3.22 -ENV IP :: -ENV DUALSTACK 1 -ENV PORT 1688 -ENV EPID "" -ENV LCID 1033 -ENV CLIENT_COUNT 26 -ENV ACTIVATION_INTERVAL 120 -ENV RENEWAL_INTERVAL 10080 +ENV IP=:: +ENV DUALSTACK=1 +ENV PORT=1688 +ENV EPID="" +ENV LCID=1033 +ENV CLIENT_COUNT=26 +ENV ACTIVATION_INTERVAL=120 +ENV RENEWAL_INTERVAL=10080 ENV HWID RANDOM -ENV LOGLEVEL INFO -ENV LOGFILE STDOUT -ENV LOGSIZE "" -ENV WEBUI 0 +ENV LOGLEVEL=INFO +ENV LOGFILE=STDOUT +ENV LOGSIZE="" +ENV WEBUI=0 COPY docker/docker-py3-kms-minimal/requirements.txt /home/py-kms/requirements.txt RUN apk add --no-cache --update \ @@ -23,7 +23,7 @@ bash \ ca-certificates \ shadow \ tzdata \ - && pip3 install --no-cache-dir -r /home/py-kms/requirements.txt \ + && pip3 install --break-system-packages --no-cache-dir -r /home/py-kms/requirements.txt \ && adduser -S py-kms -G users -s /bin/bash \ && chown py-kms:users /home/py-kms \ # Fix undefined timezone, in case the user did not mount the /etc/localtime @@ -35,6 +35,13 @@ COPY docker/healthcheck.py /usr/bin/healthcheck.py COPY docker/start.py /usr/bin/start.py RUN chmod 555 /usr/bin/entrypoint.py /usr/bin/healthcheck.py /usr/bin/start.py +# Additional permission hardening: All files read-only for the executing user +RUN chown root: -R /home/py-kms && \ + chmod 444 -R /home/py-kms && \ + chown py-kms: /home/py-kms && \ + chmod 700 /home/py-kms && \ + find /home/py-kms -type d -print -exec chmod +x {} ';' + WORKDIR /home/py-kms EXPOSE ${PORT}/tcp diff --git a/docker/docker-py3-kms/Dockerfile b/docker/docker-py3-kms/Dockerfile index 16b3ab5..547171b 100644 --- a/docker/docker-py3-kms/Dockerfile +++ b/docker/docker-py3-kms/Dockerfile @@ -1,23 +1,23 @@ # Switch to the target image -FROM alpine:3.15 +FROM alpine:3.22 ARG BUILD_COMMIT=unknown ARG BUILD_BRANCH=unknown -ENV IP :: -ENV DUALSTACK 1 -ENV PORT 1688 -ENV EPID "" -ENV LCID 1033 -ENV CLIENT_COUNT 26 -ENV ACTIVATION_INTERVAL 120 -ENV RENEWAL_INTERVAL 10080 -ENV HWID RANDOM -ENV LOGLEVEL INFO -ENV LOGFILE STDOUT -ENV LOGSIZE "" -ENV TZ America/Chicago -ENV WEBUI 1 +ENV IP=:: +ENV DUALSTACK=1 +ENV PORT=1688 +ENV EPID="" +ENV LCID=1033 +ENV CLIENT_COUNT=26 +ENV ACTIVATION_INTERVAL=120 +ENV RENEWAL_INTERVAL=10080 +ENV HWID=RANDOM +ENV LOGLEVEL=INFO +ENV LOGFILE=STDOUT +ENV LOGSIZE="" +ENV TZ=America/Chicago +ENV WEBUI=1 COPY docker/docker-py3-kms/requirements.txt /home/py-kms/ RUN apk add --no-cache --update \ @@ -28,7 +28,7 @@ RUN apk add --no-cache --update \ ca-certificates \ tzdata \ shadow \ - && pip3 install --no-cache-dir -r /home/py-kms/requirements.txt \ + && pip3 install --break-system-packages --no-cache-dir -r /home/py-kms/requirements.txt \ && mkdir /db/ \ && adduser -S py-kms -G users -s /bin/bash \ && chown py-kms:users /home/py-kms \ @@ -41,6 +41,13 @@ COPY docker/healthcheck.py /usr/bin/healthcheck.py COPY docker/start.py /usr/bin/start.py RUN chmod 555 /usr/bin/entrypoint.py /usr/bin/healthcheck.py /usr/bin/start.py +# Additional permission hardening: All files read-only for the executing user +RUN chown root: -R /home/py-kms && \ + chmod 444 -R /home/py-kms && \ + chown py-kms: /home/py-kms && \ + chmod 700 /home/py-kms && \ + find /home/py-kms -type d -print -exec chmod +x {} ';' + # Web-interface specifics COPY LICENSE /LICENSE RUN echo "$BUILD_COMMIT" > /VERSION && echo "$BUILD_BRANCH" >> /VERSION diff --git a/docker/docker-py3-kms/requirements.txt b/docker/docker-py3-kms/requirements.txt index 3210657..14b778f 100644 --- a/docker/docker-py3-kms/requirements.txt +++ b/docker/docker-py3-kms/requirements.txt @@ -1,5 +1,5 @@ -dnspython==2.6.1 -tzlocal==4.2 +dnspython==2.8.0 +tzlocal==5.3.1 -Flask==2.3.2 -gunicorn==22.0.0 \ No newline at end of file +Flask==3.1.2 +gunicorn==23.0.0 \ No newline at end of file diff --git a/docker/entrypoint.py b/docker/entrypoint.py index 8035cd0..b564966 100755 --- a/docker/entrypoint.py +++ b/docker/entrypoint.py @@ -25,29 +25,34 @@ def change_uid_grp(logger): new_gid = int(os.getenv('GID', str(gid))) new_uid = int(os.getenv('UID', str(uid))) os.chown("/home/py-kms", new_uid, new_gid) - os.chown("/usr/bin/start.py", new_uid, new_gid) + os.chmod("/home/py-kms", 0o700) if os.path.isdir(dbPath): - # Corret permissions recursively, as to access the database file, also its parent folder must be accessible - logger.debug(f'Correcting owner permissions on {dbPath}.') + # Correct permissions recursively, as to access the database file, also its parent folder must be accessible + logger.debug(f'Correcting owner permissions on {dbPath}') os.chown(dbPath, new_uid, new_gid) + os.chmod(dbPath, 0o700) # executable bit on dirs to allow interaction for root, dirs, files in os.walk(dbPath): for dName in dirs: dPath = os.path.join(root, dName) - logger.debug(f'Correcting owner permissions on {dPath}.') + logger.debug(f'Correcting owner permissions on {dPath}') os.chown(dPath, new_uid, new_gid) + os.chmod(dPath, 0o700) # executable bit on dirs to allow interaction for fName in files: fPath = os.path.join(root, fName) - logger.debug(f'Correcting owner permissions on {fPath}.') + logger.debug(f'Correcting owner permissions on {fPath}') os.chown(fPath, new_uid, new_gid) + os.chmod(fPath, 0o600) logger.debug(subprocess.check_output(['ls', '-la', dbPath]).decode()) + else: + logger.warning(f'Database path {dbPath} is not a directory, will not correct owner permissions.') if 'LOGFILE' in os.environ and os.path.exists(os.environ['LOGFILE']): # Oh, the user also wants a custom log file -> make sure start.py can access it by setting the correct permissions (777) os.chmod(os.environ['LOGFILE'], 0o777) logger.error(str(subprocess.check_output(['ls', '-la', os.environ['LOGFILE']]))) - logger.info("Setting gid to '%s'." % str(new_gid)) + # Drop actual permissions + logger.info(f"Setting gid to {new_gid}") os.setgid(new_gid) - - logger.info("Setting uid to '%s'." % str(new_uid)) + logger.info(f"Setting uid to {new_uid}") os.setuid(new_uid) def change_tz(logger): diff --git a/docs/Getting Started.md b/docs/Getting Started.md index cb1e43e..54d2b08 100644 --- a/docs/Getting Started.md +++ b/docs/Getting Started.md @@ -5,6 +5,9 @@ What follows are some guides how to start the `pykms_Server.py` script, which pr You can simply manage a daemon that runs as a background process. This can be achieved by using any of the notes below or by writing your own solution. ### Docker +![docker-pulls](https://img.shields.io/docker/pulls/pykmsorg/py-kms) +![docker-size](https://img.shields.io/docker/image-size/pykmsorg/py-kms) + If you wish to get _py-kms_ just up and running without installing any dependencies or writing own scripts: Just use Docker ! Docker also solves problems regarding the explicit IPv4 and IPv6 usage (it just supports both). The following command will download, "install" and start _py-kms_ and also keep it alive after any service disruption. diff --git a/py-kms/KmsDataBase.xml b/py-kms/KmsDataBase.xml index 511afba..fea1eee 100644 --- a/py-kms/KmsDataBase.xml +++ b/py-kms/KmsDataBase.xml @@ -1,762 +1,422 @@ + - + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - - + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - + - - - - + + + - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - + - - - - + - - - - - - - - - - - - - - - - + + - - - + - - + - - - - - + + + - - - - + + + - - - + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - - - - - + + + + + + + + + + - + + + - - + - - - - + + + - - - + + + + + + + + + - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + @@ -772,39 +432,149 @@ - + - - - - - + + + - - - - - - + + + + + - - - - - - - - - - - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -814,73 +584,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -888,7 +591,7 @@ - + @@ -896,22 +599,19 @@ - + - + - - - - + @@ -919,66 +619,59 @@ - - + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - + + - + - - + + - + - - - @@ -987,31 +680,56 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - diff --git a/py-kms/pykms_Client.py b/py-kms/pykms_Client.py index d2fe1b5..142b316 100644 --- a/py-kms/pykms_Client.py +++ b/py-kms/pykms_Client.py @@ -184,7 +184,7 @@ def client_update(): if sName == name + 'Enterprise' or \ sName == name[:6] + 'ProfessionalPlus' + name[6:]: clt_config['KMSClientSkuID'] = skuitem['Id'] - clt_config['RequiredClientCount'] = int(kmsitem['NCountPolicy']) + clt_config['RequiredClientCount'] = int(kmsitem.get('NCountPolicy', 25)) # if not given default to 25 clt_config['KMSProtocolMajorVersion'] = int(float(kmsitem['DefaultKmsProtocol'])) clt_config['KMSProtocolMinorVersion'] = 0 clt_config['KMSClientLicenseStatus'] = 2 diff --git a/py-kms/pykms_PidGenerator.py b/py-kms/pykms_PidGenerator.py index bf84187..f73102a 100644 --- a/py-kms/pykms_PidGenerator.py +++ b/py-kms/pykms_PidGenerator.py @@ -20,7 +20,7 @@ def epidGenerator(kmsId, version, lcid): for csvlkitem in csvlkitems: try: if kmsId in [ uuid.UUID(kmsitem) for kmsitem in csvlkitem['Activate'] ]: - pkeys.append( (csvlkitem['GroupId'], csvlkitem['MinKeyId'], csvlkitem['MaxKeyId'], csvlkitem['InvalidWinBuild']) ) + pkeys.append( (csvlkitem['GroupId'], csvlkitem['MinKeyId'], csvlkitem['MaxKeyId'], csvlkitem.get('InvalidWinBuild', '[]')) ) else: # fallback to Windows Server 2019 parameters. pkeys.append( ('206', '551000000', '570999999', '[0,1,2]') ) @@ -40,10 +40,11 @@ def epidGenerator(kmsId, version, lcid): hosts.append(winbuild) except KeyError: # fallback to Windows Server 2019 parameters. - hosts.append( {'BuildNumber':'17763', 'PlatformId':'3612', 'MinDate':'02/10/2018'} ) + hosts.append( {'BuildNumber':'17763', 'PlatformId':'3612', 'ReleaseDate':'2018-10-02T00:00:00Z'} ) host = random.choice(hosts) - BuildNumber, PlatformId, MinDate = host['BuildNumber'], host['PlatformId'], host['MinDate'] + + BuildNumber, PlatformId, ReleaseDate = host['BuildNumber'], host['PlatformId'], host['ReleaseDate'].rstrip("Z") # Generate Part 3 and Part 4: Product Key ID productKeyID = random.randint(MinKeyId, MaxKeyId) @@ -55,11 +56,11 @@ def epidGenerator(kmsId, version, lcid): languageCode = lcid # (C# CultureInfo.InstalledUICulture.LCID) # Generate Part 8: KMS Host Activation Date - d = datetime.datetime.strptime(MinDate, "%d/%m/%Y") + d = datetime.datetime.fromisoformat(ReleaseDate) minTime = datetime.date(d.year, d.month, d.day) # Generate Year and Day Number - randomDate = datetime.date.fromtimestamp(random.randint(time.mktime(minTime.timetuple()), time.mktime(datetime.datetime.now().timetuple()))) + randomDate = datetime.date.fromtimestamp(random.randint(int(time.mktime(minTime.timetuple())), int(time.mktime(datetime.datetime.now().timetuple())))) firstOfYear = datetime.date(randomDate.year, 1, 1) randomDayNumber = int((time.mktime(randomDate.timetuple()) - time.mktime(firstOfYear.timetuple())) / 86400 + 0.5) diff --git a/py-kms/pykms_WebUI.py b/py-kms/pykms_WebUI.py index 43285a5..06b7d7e 100644 --- a/py-kms/pykms_WebUI.py +++ b/py-kms/pykms_WebUI.py @@ -15,33 +15,34 @@ def _get_serve_count(): return _serve_count _kms_items = None -_kms_items_ignored = None +_kms_items_noglvk = None def _get_kms_items_cache(): - global _kms_items, _kms_items_ignored + global _kms_items, _kms_items_noglvk if _kms_items is None: - _kms_items = {} - _kms_items_ignored = 0 - queue = [kmsDB2Dict()] - while len(queue): - item = queue.pop(0) - if isinstance(item, list): - for i in item: - queue.append(i) - elif isinstance(item, dict): - if 'KmsItems' in item: - queue.append(item['KmsItems']) - elif 'SkuItems' in item: - queue.append(item['SkuItems']) - elif 'Gvlk' in item: - if len(item['Gvlk']): - _kms_items[item['DisplayName']] = item['Gvlk'] - else: - _kms_items_ignored += 1 - #else: - # print(item) - else: - raise NotImplementedError(f'Unknown type: {type(item)}') - return _kms_items, _kms_items_ignored + _kms_items = {} # {group: str -> {product: str -> gvlk: str}} + _kms_items_noglvk = 0 + for section in kmsDB2Dict(): + for element in section: + if "KmsItems" in element: + for product in element["KmsItems"]: + group_name = product["DisplayName"] + items = {} + for item in product["SkuItems"]: + items[item["DisplayName"]] = item["Gvlk"] + if not item["Gvlk"]: + _kms_items_noglvk += 1 + if len(items) == 0: + continue + if group_name not in _kms_items: + _kms_items[group_name] = {} + _kms_items[group_name].update(items) + elif "DisplayName" in element and "BuildNumber" in element and "PlatformId" in element: + pass # these are WinBuilds + elif "DisplayName" in element and "Activate" in element: + pass # these are CsvlkItems + else: + raise NotImplementedError(f'Unknown element: {element}') + return _kms_items, _kms_items_noglvk app = Flask('pykms_webui') app.jinja_env.globals['start_time'] = datetime.datetime.now() @@ -90,7 +91,7 @@ def root(): count_clients=countClients, count_clients_windows=countClientsWindows, count_clients_office=countClientsOffice, - count_projects=len(_get_kms_items_cache()[0]) + count_projects=sum([len(entries) for entries in _get_kms_items_cache()[0].values()]) ), 200 if error is None else 500 @app.route('/readyz') @@ -125,15 +126,15 @@ def license(): @app.route('/products') def products(): _increase_serve_count() - items, ignored = _get_kms_items_cache() - countProducts = len(items) - countProductsWindows = len([i for i in items if 'windows' in i.lower()]) - countProductsOffice = len([i for i in items if 'office' in i.lower()]) + items, noglvk = _get_kms_items_cache() + countProducts = sum([len(entries) for entries in items.values()]) + countProductsWindows = sum([len(entries) for (name, entries) in items.items() if 'windows' in name.lower()]) + countProductsOffice = sum([len(entries) for (name, entries) in items.items() if 'office' in name.lower()]) return render_template( 'products.html', path='/products/', products=items, - filtered=ignored, + filtered=noglvk, count_products=countProducts, count_products_windows=countProductsWindows, count_products_office=countProductsOffice diff --git a/py-kms/templates/products.html b/py-kms/templates/products.html index 9665304..d106ed1 100644 --- a/py-kms/templates/products.html +++ b/py-kms/templates/products.html @@ -32,22 +32,36 @@
+ + +{% for group_name, group_products in products | dictsort %} +

{{ group_name }}

- - + + - {% for name, gvlk in products | dictsort %} - {% if gvlk %} - - - - - {% endif %} - {% endfor %} + {% for name, gvlk in group_products | dictsort %} + + + + + {% endfor %}
NameGVLKNameGVLK
{{ name }}
{{ gvlk }}
{{ name }} + {% if gvlk %} +
{{ gvlk }}
{% endif %} +
-{% endblock %} \ No newline at end of file +{% endfor %} +{% endblock %}