Add Python implementation (#21)
This commit is contained in:
parent
ab6b10b746
commit
385081650c
6 changed files with 104 additions and 14 deletions
44
.github/workflows/builder.yml
vendored
44
.github/workflows/builder.yml
vendored
|
@ -3,49 +3,51 @@ name: Wulkanowy QR
|
|||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ master ]
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
php:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '7.4'
|
||||
php-version: "7.4"
|
||||
- name: Install PHP dependencies
|
||||
run: composer install
|
||||
- name: Run PHP tests
|
||||
run: ./vendor/bin/phpunit php/tests
|
||||
|
||||
node:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '19'
|
||||
node-version: "19"
|
||||
- name: Install Node.js dependencies using Yarn
|
||||
working-directory: ./node
|
||||
run: yarn install
|
||||
- name: Run Node.js tests
|
||||
working-directory: ./node
|
||||
run: yarn test
|
||||
|
||||
jvm:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: '11'
|
||||
distribution: "zulu"
|
||||
java-version: "11"
|
||||
- name: Run JVM tests
|
||||
working-directory: ./jvm
|
||||
run: ./gradlew check jacocoTestReport
|
||||
|
@ -54,30 +56,44 @@ jobs:
|
|||
with:
|
||||
name: test-results
|
||||
path: ./build/test-results
|
||||
|
||||
dart:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Dart
|
||||
uses: dart-lang/setup-dart@v1.3
|
||||
with:
|
||||
sdk: '2.10.0'
|
||||
sdk: "2.10.0"
|
||||
- name: Install Dart dependencies
|
||||
working-directory: ./dart
|
||||
run: pub get
|
||||
- name: Run Dart tests
|
||||
working-directory: ./dart
|
||||
run: pub run test
|
||||
dotnet:
|
||||
|
||||
dotnet:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '3.1.407'
|
||||
dotnet-version: "3.1.407"
|
||||
- name: Run .NET tests
|
||||
working-directory: ./dotnet
|
||||
run: dotnet test
|
||||
|
||||
python:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
working-directory: ./python
|
||||
run: pip install .
|
||||
- name: Run Python tests
|
||||
working-directory: ./python
|
||||
run: python -m unittest test
|
||||
|
|
1
python/.gitignore
vendored
Normal file
1
python/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
__pycache__/
|
19
python/README.md
Normal file
19
python/README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# UONET+ QR Code converter for Python
|
||||
|
||||
[![PyPI](https://img.shields.io/pypi/v/wulkanowy-qr.svg?style=flat-square)](https://pypi.org/project/wulkanowy-qr/)
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
pip install wulkanowy-qr
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```pycon
|
||||
>>> import wulkanowy_qr
|
||||
>>> wulkanowy_qr.encode("0123456789ABCDEF", "CERT#https://api.fakelog.cf/Default/mobile-api#FK100000#ENDCERT")
|
||||
'27Grk6d8ZDely5eeF7j2ngWrWV9eZa5Dz9ZmuiBavysDp74TCr6EHJOs6TaIXFh3HsROWSM11pv3cPvRGSi7Nw=='
|
||||
>>> wulkanowy_qr.decode("0123456789ABCDEF", "27Grk6d8ZDely5eeF7j2ngWrWV9eZa5Dz9ZmuiBavysDp74TCr6EHJOs6TaIXFh3HsROWSM11pv3cPvRGSi7Nw==")
|
||||
'CERT#https://api.fakelog.cf/Default/mobile-api#FK100000#ENDCERT'
|
||||
```
|
13
python/pyproject.toml
Normal file
13
python/pyproject.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
[project]
|
||||
name = "wulkanowy-qr"
|
||||
version = "1.0.1"
|
||||
description = "UONET+ QR Code converter for Python"
|
||||
readme = "README.md"
|
||||
license = { text = "MIT" }
|
||||
authors = [{ name = "JelNiSlaw", email = "jelnislaw@gmail.com" }]
|
||||
urls = { Repository = "https://github.com/wulkanowy/qr/tree/master/python" }
|
||||
dependencies = ["pycryptodome~=3.15"]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools"]
|
||||
build-backend = "setuptools.build_meta"
|
25
python/test/__init__.py
Normal file
25
python/test/__init__.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
import unittest
|
||||
|
||||
import wulkanowy_qr
|
||||
|
||||
PASSWORD = "0123456789ABCDEF"
|
||||
CONTENT = "CERT#https://api.fakelog.cf/Default/mobile-api#FK100000#ENDCERT"
|
||||
ENCODED = "27Grk6d8ZDely5eeF7j2ngWrWV9eZa5Dz9ZmuiBavysDp74TCr6EHJOs6TaIXFh3HsROWSM11pv3cPvRGSi7Nw=="
|
||||
|
||||
|
||||
class TestEncoding(unittest.TestCase):
|
||||
def test_encode(self) -> None:
|
||||
self.assertEqual(wulkanowy_qr.encode(PASSWORD, CONTENT), ENCODED)
|
||||
|
||||
def test_decode(self) -> None:
|
||||
self.assertEqual(wulkanowy_qr.decode(PASSWORD, ENCODED), CONTENT)
|
||||
|
||||
def test_both(self) -> None:
|
||||
self.assertEqual(
|
||||
CONTENT,
|
||||
wulkanowy_qr.decode(PASSWORD, wulkanowy_qr.encode(PASSWORD, CONTENT)),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
16
python/wulkanowy_qr/__init__.py
Normal file
16
python/wulkanowy_qr/__init__.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
import base64
|
||||
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util import Padding
|
||||
|
||||
|
||||
def encode(password: str, content: str) -> str:
|
||||
cipher = AES.new(password.encode(), AES.MODE_ECB)
|
||||
bytes = cipher.encrypt(Padding.pad(content.encode(), 16))
|
||||
return base64.b64encode(bytes).decode()
|
||||
|
||||
|
||||
def decode(password: str, content: str) -> str:
|
||||
cipher = AES.new(password.encode(), AES.MODE_ECB)
|
||||
bytes = cipher.decrypt(base64.b64decode(content))
|
||||
return Padding.unpad(bytes, 16).decode()
|
Loading…
Reference in a new issue