mitid-connect 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mitid_connect-0.0.1/.git_archival.txt +3 -0
- mitid_connect-0.0.1/.gitattributes +2 -0
- mitid_connect-0.0.1/.github/dependabot.yml +24 -0
- mitid_connect-0.0.1/.github/release.yml +25 -0
- mitid_connect-0.0.1/.github/rulesets/branch-names.json +26 -0
- mitid_connect-0.0.1/.github/rulesets/main.json +63 -0
- mitid_connect-0.0.1/.github/workflows/close-inactive-issues.yml +30 -0
- mitid_connect-0.0.1/.github/workflows/library-released.yml +32 -0
- mitid_connect-0.0.1/.github/workflows/release-drafter.yml +28 -0
- mitid_connect-0.0.1/.github/workflows/release.yml +91 -0
- mitid_connect-0.0.1/.github/workflows/tests.yml +42 -0
- mitid_connect-0.0.1/.gitignore +12 -0
- mitid_connect-0.0.1/CLAUDE.md +147 -0
- mitid_connect-0.0.1/LICENSE +22 -0
- mitid_connect-0.0.1/PKG-INFO +55 -0
- mitid_connect-0.0.1/README.md +24 -0
- mitid_connect-0.0.1/pyproject.toml +76 -0
- mitid_connect-0.0.1/requirements-test.txt +11 -0
- mitid_connect-0.0.1/setup.cfg +4 -0
- mitid_connect-0.0.1/src/mitid_connect/__init__.py +29 -0
- mitid_connect-0.0.1/src/mitid_connect/browser_client.py +813 -0
- mitid_connect-0.0.1/src/mitid_connect/helpers.py +98 -0
- mitid_connect-0.0.1/src/mitid_connect/py.typed +0 -0
- mitid_connect-0.0.1/src/mitid_connect/srp.py +216 -0
- mitid_connect-0.0.1/src/mitid_connect.egg-info/PKG-INFO +55 -0
- mitid_connect-0.0.1/src/mitid_connect.egg-info/SOURCES.txt +31 -0
- mitid_connect-0.0.1/src/mitid_connect.egg-info/dependency_links.txt +1 -0
- mitid_connect-0.0.1/src/mitid_connect.egg-info/requires.txt +5 -0
- mitid_connect-0.0.1/src/mitid_connect.egg-info/scm_file_list.json +28 -0
- mitid_connect-0.0.1/src/mitid_connect.egg-info/scm_version.json +8 -0
- mitid_connect-0.0.1/src/mitid_connect.egg-info/top_level.txt +1 -0
- mitid_connect-0.0.1/tests/test_helpers.py +13 -0
- mitid_connect-0.0.1/tests/test_srp.py +47 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Proposes updates to the pinned actions and test tools as pull requests, which the tests then
|
|
2
|
+
# check before anything is merged.
|
|
3
|
+
#
|
|
4
|
+
# Shared by every library of the owner, from HairingX/workflows; this file is a copy of its
|
|
5
|
+
# template and is checked to stay so.
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: github-actions
|
|
9
|
+
directory: /
|
|
10
|
+
schedule:
|
|
11
|
+
interval: weekly
|
|
12
|
+
labels:
|
|
13
|
+
- dependencies
|
|
14
|
+
assignees:
|
|
15
|
+
- HairingX
|
|
16
|
+
|
|
17
|
+
- package-ecosystem: pip
|
|
18
|
+
directory: /
|
|
19
|
+
schedule:
|
|
20
|
+
interval: weekly
|
|
21
|
+
labels:
|
|
22
|
+
- dependencies
|
|
23
|
+
assignees:
|
|
24
|
+
- HairingX
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# How GitHub groups a release's notes: each pull request by its labels.
|
|
2
|
+
changelog:
|
|
3
|
+
# The notes are for users: what is changed for them, not work on the repository itself.
|
|
4
|
+
exclude:
|
|
5
|
+
labels:
|
|
6
|
+
- skip-changelog
|
|
7
|
+
- chore
|
|
8
|
+
- documentation
|
|
9
|
+
- dependencies
|
|
10
|
+
categories:
|
|
11
|
+
- title: 🛠 Breaking Changes
|
|
12
|
+
labels:
|
|
13
|
+
- breaking-change
|
|
14
|
+
- title: 🚀 Features
|
|
15
|
+
labels:
|
|
16
|
+
- feature request
|
|
17
|
+
- enhancement
|
|
18
|
+
- title: 🐛 Bug Fixes
|
|
19
|
+
labels:
|
|
20
|
+
- bug
|
|
21
|
+
- fix
|
|
22
|
+
- bugfix
|
|
23
|
+
- title: Other Changes
|
|
24
|
+
labels:
|
|
25
|
+
- "*"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Branch names",
|
|
3
|
+
"target": "branch",
|
|
4
|
+
"enforcement": "active",
|
|
5
|
+
"conditions": {
|
|
6
|
+
"ref_name": {
|
|
7
|
+
"include": [
|
|
8
|
+
"~ALL"
|
|
9
|
+
],
|
|
10
|
+
"exclude": [
|
|
11
|
+
"refs/heads/main",
|
|
12
|
+
"refs/heads/feature/**/*",
|
|
13
|
+
"refs/heads/fix/**/*",
|
|
14
|
+
"refs/heads/docs/**/*",
|
|
15
|
+
"refs/heads/chore/**/*",
|
|
16
|
+
"refs/heads/dependabot/**/*"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"bypass_actors": [],
|
|
21
|
+
"rules": [
|
|
22
|
+
{
|
|
23
|
+
"type": "creation"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "main: pull requests only",
|
|
3
|
+
"target": "branch",
|
|
4
|
+
"enforcement": "active",
|
|
5
|
+
"conditions": {
|
|
6
|
+
"ref_name": {
|
|
7
|
+
"include": [
|
|
8
|
+
"~DEFAULT_BRANCH"
|
|
9
|
+
],
|
|
10
|
+
"exclude": []
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"bypass_actors": [
|
|
14
|
+
{
|
|
15
|
+
"actor_id": 5,
|
|
16
|
+
"actor_type": "RepositoryRole",
|
|
17
|
+
"bypass_mode": "pull_request"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"rules": [
|
|
21
|
+
{
|
|
22
|
+
"type": "deletion"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "non_fast_forward"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "pull_request",
|
|
29
|
+
"parameters": {
|
|
30
|
+
"required_approving_review_count": 0,
|
|
31
|
+
"dismiss_stale_reviews_on_push": false,
|
|
32
|
+
"require_code_owner_review": false,
|
|
33
|
+
"require_last_push_approval": false,
|
|
34
|
+
"required_review_thread_resolution": false
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"type": "required_status_checks",
|
|
39
|
+
"parameters": {
|
|
40
|
+
"strict_required_status_checks_policy": false,
|
|
41
|
+
"do_not_enforce_on_create": false,
|
|
42
|
+
"required_status_checks": [
|
|
43
|
+
{
|
|
44
|
+
"context": "Python 3.12",
|
|
45
|
+
"integration_id": 15368
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"context": "Python 3.13",
|
|
49
|
+
"integration_id": 15368
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"context": "Python 3.14",
|
|
53
|
+
"integration_id": 15368
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"context": "Libraries released and pinned",
|
|
57
|
+
"integration_id": 15368
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Close inactive issues
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
schedule:
|
|
6
|
+
- cron: "30 1 * * *"
|
|
7
|
+
|
|
8
|
+
permissions: {}
|
|
9
|
+
|
|
10
|
+
# The shell given explicitly, so GitHub runs every step with pipefail.
|
|
11
|
+
defaults:
|
|
12
|
+
run:
|
|
13
|
+
shell: bash
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
close-issues:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
permissions:
|
|
19
|
+
issues: write
|
|
20
|
+
pull-requests: write
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/stale@v11
|
|
23
|
+
with:
|
|
24
|
+
days-before-issue-stale: 30
|
|
25
|
+
days-before-issue-close: 14
|
|
26
|
+
stale-issue-label: "stale"
|
|
27
|
+
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
|
|
28
|
+
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
|
|
29
|
+
days-before-pr-stale: -1
|
|
30
|
+
days-before-pr-close: -1
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Library released
|
|
2
|
+
|
|
3
|
+
# A pull request is merged only once every library developed alongside the package comes from
|
|
4
|
+
# its release, not from a branch of the pull request's name.
|
|
5
|
+
#
|
|
6
|
+
# The workflows and the tools are shared by every library of the owner, from
|
|
7
|
+
# HairingX/workflows; this file is a copy of its template and is checked to stay so.
|
|
8
|
+
on:
|
|
9
|
+
pull_request:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
# The shell given explicitly, so GitHub runs every step with pipefail.
|
|
15
|
+
defaults:
|
|
16
|
+
run:
|
|
17
|
+
shell: bash
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
released:
|
|
21
|
+
name: Libraries released and pinned
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- name: Check out repository
|
|
25
|
+
uses: actions/checkout@v7
|
|
26
|
+
with:
|
|
27
|
+
persist-credentials: false
|
|
28
|
+
|
|
29
|
+
- name: No library from a branch
|
|
30
|
+
uses: HairingX/workflows/python/actions/libraries-released@v2
|
|
31
|
+
with:
|
|
32
|
+
branch: ${{ github.head_ref }}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Release Drafter
|
|
2
|
+
|
|
3
|
+
# Keeps a draft release proposing the next version, and labels pull requests by their branch's
|
|
4
|
+
# name. The draft is never published by hand: the Release workflow publishes it.
|
|
5
|
+
#
|
|
6
|
+
# The workflows and the tools are shared by every repository of the owner, from
|
|
7
|
+
# HairingX/workflows; this file is a copy of its template and is checked to stay so.
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches:
|
|
11
|
+
- main
|
|
12
|
+
pull_request:
|
|
13
|
+
types: [opened, reopened, synchronize]
|
|
14
|
+
|
|
15
|
+
permissions: {}
|
|
16
|
+
|
|
17
|
+
# The shell given explicitly, so GitHub runs every step with pipefail.
|
|
18
|
+
defaults:
|
|
19
|
+
run:
|
|
20
|
+
shell: bash
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
drafter:
|
|
24
|
+
name: Release Drafter
|
|
25
|
+
permissions:
|
|
26
|
+
contents: write
|
|
27
|
+
pull-requests: write
|
|
28
|
+
uses: HairingX/workflows/.github/workflows/release-drafter.yml@v2
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Run this from the Actions tab, on main, once the maintainer has approved the draft release and
|
|
4
|
+
# its version. Never publish the draft release by hand: the package takes its version from the
|
|
5
|
+
# tag, and only this workflow tags a tested commit.
|
|
6
|
+
#
|
|
7
|
+
# The file name matters: PyPI trusted publishing is bound to this repository, this workflow file
|
|
8
|
+
# and the pypi environment, and takes no reusable workflow, so the upload runs here.
|
|
9
|
+
#
|
|
10
|
+
# The workflows and the tools are shared by every library of the owner, from
|
|
11
|
+
# HairingX/workflows; this file is a copy of its template and is checked to stay so.
|
|
12
|
+
on:
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
inputs:
|
|
15
|
+
release:
|
|
16
|
+
description: >-
|
|
17
|
+
What to release. The version is worked out from the tags, PyPI and the draft release:
|
|
18
|
+
the next release candidate, or the final release that ends the series.
|
|
19
|
+
required: true
|
|
20
|
+
type: choice
|
|
21
|
+
options:
|
|
22
|
+
- release candidate
|
|
23
|
+
- final release
|
|
24
|
+
default: release candidate
|
|
25
|
+
version:
|
|
26
|
+
description: >-
|
|
27
|
+
Override, only for a new major version, which is never worked out, or when the version
|
|
28
|
+
worked out is wrong: canonical PEP 440 without a v, such as 1.0.0 or 1.0.0rc1, of the
|
|
29
|
+
kind chosen above. It must still be higher than every version tagged or on PyPI.
|
|
30
|
+
required: false
|
|
31
|
+
type: string
|
|
32
|
+
|
|
33
|
+
permissions: {}
|
|
34
|
+
|
|
35
|
+
# GitHub keeps one waiting run per group: a third dispatch cancels the one waiting.
|
|
36
|
+
concurrency:
|
|
37
|
+
group: release
|
|
38
|
+
cancel-in-progress: false
|
|
39
|
+
|
|
40
|
+
# The shell given explicitly, so GitHub runs every step with pipefail.
|
|
41
|
+
defaults:
|
|
42
|
+
run:
|
|
43
|
+
shell: bash
|
|
44
|
+
|
|
45
|
+
jobs:
|
|
46
|
+
release:
|
|
47
|
+
name: Release
|
|
48
|
+
permissions:
|
|
49
|
+
contents: write
|
|
50
|
+
pull-requests: read
|
|
51
|
+
actions: read
|
|
52
|
+
uses: HairingX/workflows/.github/workflows/python-release.yml@v2
|
|
53
|
+
with:
|
|
54
|
+
release: ${{ inputs.release }}
|
|
55
|
+
version: ${{ inputs.version }}
|
|
56
|
+
|
|
57
|
+
pypi:
|
|
58
|
+
name: Publish to PyPI
|
|
59
|
+
needs: release
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
permissions:
|
|
62
|
+
# Mandatory for trusted publishing.
|
|
63
|
+
id-token: write
|
|
64
|
+
environment:
|
|
65
|
+
name: pypi
|
|
66
|
+
url: https://pypi.org/p/${{ needs.release.outputs.package }}
|
|
67
|
+
steps:
|
|
68
|
+
- name: Fetch the distributions
|
|
69
|
+
uses: actions/download-artifact@v8
|
|
70
|
+
with:
|
|
71
|
+
name: dist
|
|
72
|
+
path: dist/
|
|
73
|
+
|
|
74
|
+
# A re-run finds the version it uploaded before.
|
|
75
|
+
- name: Publish
|
|
76
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
77
|
+
with:
|
|
78
|
+
skip-existing: true
|
|
79
|
+
|
|
80
|
+
github-release:
|
|
81
|
+
name: GitHub release
|
|
82
|
+
needs: [release, pypi]
|
|
83
|
+
permissions:
|
|
84
|
+
contents: write
|
|
85
|
+
uses: HairingX/workflows/.github/workflows/python-github-release.yml@v2
|
|
86
|
+
with:
|
|
87
|
+
tag: ${{ needs.release.outputs.tag }}
|
|
88
|
+
prerelease: ${{ needs.release.outputs.prerelease }}
|
|
89
|
+
previous_tag: ${{ needs.release.outputs.previous_tag }}
|
|
90
|
+
draft_id: ${{ needs.release.outputs.draft_id }}
|
|
91
|
+
draft_body: ${{ needs.release.outputs.draft_body }}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
# The workflows and the tools are shared by every library of the owner, from
|
|
4
|
+
# HairingX/workflows; this file is a copy of its template and is checked to stay so.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
pull_request:
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: tests-${{ github.event_name }}-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
# The shell given explicitly, so GitHub runs every step with pipefail.
|
|
18
|
+
defaults:
|
|
19
|
+
run:
|
|
20
|
+
shell: bash
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
test:
|
|
24
|
+
name: Python ${{ matrix.python-version }}
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
strategy:
|
|
27
|
+
fail-fast: false
|
|
28
|
+
matrix:
|
|
29
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
30
|
+
steps:
|
|
31
|
+
- name: Check out repository, with every tag
|
|
32
|
+
uses: actions/checkout@v7
|
|
33
|
+
with:
|
|
34
|
+
persist-credentials: false
|
|
35
|
+
# setuptools-scm works the package's version out from the tags.
|
|
36
|
+
fetch-depth: 0
|
|
37
|
+
|
|
38
|
+
- name: Tests and type check
|
|
39
|
+
uses: HairingX/workflows/python/actions/tests@v2
|
|
40
|
+
with:
|
|
41
|
+
python-version: ${{ matrix.python-version }}
|
|
42
|
+
branch: ${{ github.head_ref || github.ref_name }}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Conventions for this repository
|
|
2
|
+
|
|
3
|
+
A Python library that logs in through MitID: an unofficial implementation of MitID's browser
|
|
4
|
+
client, which authenticates with the MitID app (QR code or one-time code) or a code token and
|
|
5
|
+
gives back the authorization code the service being logged in to exchanges for its own tokens.
|
|
6
|
+
It knows nothing of any one service; `aula_connect` is one that uses it.
|
|
7
|
+
|
|
8
|
+
## This library
|
|
9
|
+
|
|
10
|
+
- A MitID username, password, code and every token are credentials: never logged, never in a
|
|
11
|
+
tracked file. A live test takes them from environment variables and skips without them.
|
|
12
|
+
- It talks only to MitID (`www.mitid.dk`) and, for choosing between identities, to the
|
|
13
|
+
NemLog-in page the service's flow is on.
|
|
14
|
+
- The code is MIT-licensed. It carries on Hundter's MitID-BrowserClient, whose copyright stays
|
|
15
|
+
in `LICENSE`.
|
|
16
|
+
|
|
17
|
+
<!-- BEGIN HairingX/workflows: shared; edit it there -->
|
|
18
|
+
## Shared by every library
|
|
19
|
+
|
|
20
|
+
This section, the workflows and the release tools are the same in every Python library of the
|
|
21
|
+
owner. They come from `HairingX/workflows`: the workflows in `.github/` are copies of its
|
|
22
|
+
template, which call its reusable workflows and actions at `@v2`, and this section is a copy of
|
|
23
|
+
its `python/template/CLAUDE.md`. The tests check that the copies agree; a change to any of them is
|
|
24
|
+
made there, released, and synced into every repository with its
|
|
25
|
+
`common/tools/template.py sync python`. What is this repository's own is above this section.
|
|
26
|
+
|
|
27
|
+
## Comments and docstrings
|
|
28
|
+
|
|
29
|
+
Based on PEP 8 (Comments), PEP 257 (Docstring Conventions) and the Google Python Style Guide
|
|
30
|
+
(3.8 Comments and Docstrings).
|
|
31
|
+
|
|
32
|
+
**Docstrings describe the unit's own contract, and nothing else.**
|
|
33
|
+
- Every public module, class, function and method has one.
|
|
34
|
+
- The first line is a one-sentence summary. Add more only when a caller needs it: arguments,
|
|
35
|
+
return value, exceptions raised, side effects, invariants.
|
|
36
|
+
- Use Google style sections (`Args:`, `Returns:`, `Raises:`) only when they say something the
|
|
37
|
+
signature and type hints do not. Never repeat types; the hints carry them.
|
|
38
|
+
- Describe what the unit does, not who calls it, how other classes use its data, or where its
|
|
39
|
+
result ends up. That knowledge belongs to those other units and goes stale here.
|
|
40
|
+
|
|
41
|
+
**Comments explain why, never what.**
|
|
42
|
+
- Write one only where the code cannot say it: a protocol quirk, a non-obvious constraint, the
|
|
43
|
+
reason for an order of operations.
|
|
44
|
+
- No history: no "used to", "previously", "the old code", "this was a bug". Version control
|
|
45
|
+
holds history; a regression test's name holds the reason it exists.
|
|
46
|
+
- No references to other files, classes, line numbers or design-document sections. They rot the
|
|
47
|
+
moment the other side changes.
|
|
48
|
+
- No commented-out code. No TODO without an issue reference.
|
|
49
|
+
|
|
50
|
+
**Keep them short.** A comment longer than a few lines is design rationale; it belongs in
|
|
51
|
+
`docs/`, where it can cover several modules at once.
|
|
52
|
+
|
|
53
|
+
**Tests.** The test name states the behaviour. Add a docstring only when the reason is not
|
|
54
|
+
obvious from the name - one or two lines, no narrative.
|
|
55
|
+
|
|
56
|
+
## Conventions
|
|
57
|
+
|
|
58
|
+
- All documentation, comments and commit messages are in English.
|
|
59
|
+
- The package lives in `src/<package>/`, ships its types (`py.typed`), and supports Python 3.12
|
|
60
|
+
and later (`requires-python = ">=3.12"`); the tests run on 3.12, 3.13 and 3.14.
|
|
61
|
+
- pyright strict must report 0 errors (`pyright`); the configuration is in `pyproject.toml`.
|
|
62
|
+
No `# type: ignore` and no rule turned off.
|
|
63
|
+
- The tests are pytest, in `tests/`, and cover every line of the package; the build fails below
|
|
64
|
+
100%. They import the installed package, as its users do, never `src.<package>`: a packaging
|
|
65
|
+
mistake then fails a test before a release. Tests that need a real device are marked `live`,
|
|
66
|
+
skip themselves without one, and never run in CI.
|
|
67
|
+
- A repository on its way to this standard says so under `[tool.hairingx-workflows]` in
|
|
68
|
+
`pyproject.toml`: `transition` says why, and `coverage` the percentage its tests must reach
|
|
69
|
+
meanwhile; pyright, still strict, may leave the files listed in `[tool.pyright] ignore`
|
|
70
|
+
unchecked. Every run warns while it lasts. Each pull request raises the coverage and takes
|
|
71
|
+
files off the list, never the reverse, until the transition is removed.
|
|
72
|
+
- Every problem found gets a test that fails without the fix.
|
|
73
|
+
- The test tools are pinned with `==` in `requirements-test.txt`, pyright, pytest and
|
|
74
|
+
pytest-cov among them: `pip install -e . -r requirements-test.txt`.
|
|
75
|
+
- No real IP addresses, hostnames, serial numbers, email addresses or credentials in tracked
|
|
76
|
+
files; real values live in a gitignored file or in environment variables. Examples use the
|
|
77
|
+
documentation ranges, such as 192.0.2.0/24. A credential is never logged.
|
|
78
|
+
|
|
79
|
+
## Releasing
|
|
80
|
+
|
|
81
|
+
**The version is the release's tag, and the draft release is never published by hand.** The
|
|
82
|
+
package has no version in a file: setuptools-scm works it out from the tags when it is built, so a
|
|
83
|
+
checkout between releases says a development version such as `0.2.1.dev3+g1a2b3c4`.
|
|
84
|
+
|
|
85
|
+
1. Merge pull requests into `main`. Release Drafter keeps a draft release proposing the next
|
|
86
|
+
version: a minor bump for the label `breaking-change` or `minor`, a patch otherwise.
|
|
87
|
+
**A new major version is never worked out**, as a label placed wrongly must not release one;
|
|
88
|
+
type it into Release as the override.
|
|
89
|
+
2. Wait until the Release Drafter run on `main` has finished. Release refuses a draft that is not
|
|
90
|
+
up to date with `main`.
|
|
91
|
+
3. Show the maintainer the draft's notes and its version, and get explicit approval before
|
|
92
|
+
running Release.
|
|
93
|
+
4. Run the **Release** workflow from the Actions tab, on `main`, and choose **release
|
|
94
|
+
candidate** or **final release**. It works out the version: the next release candidate of the
|
|
95
|
+
open series (`0.2.0rc1` -> `0.2.0rc2`), or the final release that ends it (`0.2.0`); a draft
|
|
96
|
+
naming a higher version starts a new series. Type a version only for a new major, or to
|
|
97
|
+
override one worked out wrongly: canonical PEP 440, of the kind chosen.
|
|
98
|
+
|
|
99
|
+
Release refuses any version not higher than every version tagged or on PyPI, yanked ones
|
|
100
|
+
included, and a version with no pull request merged since the release before it - for a final
|
|
101
|
+
release, the final release before it. It runs the tests on the exact commit it releases, tags
|
|
102
|
+
that commit, builds, checks that the built package says the version, and only then pushes the
|
|
103
|
+
tag - nothing is pushed to `main`. Then PyPI, then the GitHub release with the distributions,
|
|
104
|
+
marked as a pre-release where it is one.
|
|
105
|
+
|
|
106
|
+
A release candidate's notes are written by GitHub from the pull requests merged since the
|
|
107
|
+
previous release candidate or final release, grouped by label as `.github/release.yml` says, and
|
|
108
|
+
the draft is kept. A final release's notes are the draft's - the first final release says only
|
|
109
|
+
that it is the initial release - and the final release deletes the draft. To change what a
|
|
110
|
+
release says, change the pull requests: the title is the line, the labels decide the section.
|
|
111
|
+
|
|
112
|
+
If publishing fails part-way, **Re-run failed jobs** resumes it: the tag, PyPI and the GitHub
|
|
113
|
+
release each accept what an earlier attempt already did.
|
|
114
|
+
|
|
115
|
+
PyPI trusted publishing is bound to this repository, the workflow file `release.yml` and the
|
|
116
|
+
`pypi` environment: renaming either breaks the upload. Actions are referred to by their major
|
|
117
|
+
version; Dependabot proposes a new major, and updates to the test tools, as pull requests.
|
|
118
|
+
|
|
119
|
+
## Libraries developed together
|
|
120
|
+
|
|
121
|
+
A library this one depends on and develops alongside is listed, in install order, under
|
|
122
|
+
`[tool.hairingx-workflows] libraries` in `pyproject.toml`. A development branch is tested with
|
|
123
|
+
that library's branch of the same name, where it has one, over its release; the check
|
|
124
|
+
"Libraries released and pinned" then fails until the library is released, its version required
|
|
125
|
+
in `pyproject.toml`, and its branch deleted. **Release a library first**, then require its
|
|
126
|
+
version here.
|
|
127
|
+
|
|
128
|
+
## Branches and pull requests
|
|
129
|
+
|
|
130
|
+
- Every change goes through a branch and a pull request: `main` takes no push. The ruleset in
|
|
131
|
+
`.github/rulesets/main.json` enforces it, with the checks "Python 3.12", "Python 3.13",
|
|
132
|
+
"Python 3.14" and "Libraries released and pinned" required; its only bypass is the owner's,
|
|
133
|
+
and only for merging a pull request. A change to what a user gets - the library's code or
|
|
134
|
+
documentation - comes with its tests.
|
|
135
|
+
- Name every branch by the kind of change, as the release draft's labels follow the name;
|
|
136
|
+
`.github/rulesets/branch-names.json` refuses any other name. `feature/<what>` is labelled
|
|
137
|
+
`feature request`, `fix/<what>` is labelled `bug`, `docs/<what>` is labelled `documentation`,
|
|
138
|
+
and `chore/<what>` - CI, tooling, anything that stays in the repository - is labelled `chore`.
|
|
139
|
+
The release notes list features and fixes; documentation, chores and Dependabot's
|
|
140
|
+
`dependencies` are left out. A change to what a user installs, such as a new dependency, is a
|
|
141
|
+
`fix/` or a `feature/`, never a `chore/`.
|
|
142
|
+
- A pull request's text describes only its own change: what it does and how it was tested. Never
|
|
143
|
+
releases to come, merge order, or other repositories.
|
|
144
|
+
- Put `breaking-change` on a pull request that breaks the API - a `feature/` or `fix/` one, as a
|
|
145
|
+
chore is left out of the notes - and `minor` on one that needs a minor bump; both give a minor
|
|
146
|
+
bump, and a patch is the default. No label gives a major.
|
|
147
|
+
<!-- END HairingX/workflows -->
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Hundter, the author of MitID-BrowserClient, which this library carries on
|
|
4
|
+
Copyright (c) 2026 HairingX
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mitid_connect
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Log in through MitID from Python: an unofficial implementation of MitID's browser client, with the MitID app or a code token.
|
|
5
|
+
Author: HairingX
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/HairingX/mitid_connect
|
|
8
|
+
Project-URL: Source, https://github.com/HairingX/mitid_connect
|
|
9
|
+
Project-URL: Issues, https://github.com/HairingX/mitid_connect/issues
|
|
10
|
+
Project-URL: Releases, https://github.com/HairingX/mitid_connect/releases
|
|
11
|
+
Keywords: mitid,nemlog-in,login,denmark
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.12
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: beautifulsoup4>=4.12.0
|
|
26
|
+
Requires-Dist: lxml>=5.0.0
|
|
27
|
+
Requires-Dist: pycryptodomex>=3.24.1
|
|
28
|
+
Requires-Dist: qrcode>=8.2
|
|
29
|
+
Requires-Dist: requests>=2.31.0
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# mitid_connect
|
|
33
|
+
|
|
34
|
+
Log in through [MitID](https://www.mitid.dk) from Python: an unofficial implementation of MitID's
|
|
35
|
+
browser client. It authenticates with the MitID app - by QR code or one-time code - or with a
|
|
36
|
+
code token, and gives back the authorization code that the service being logged in to exchanges
|
|
37
|
+
for its own tokens.
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from mitid_connect import BrowserClient
|
|
41
|
+
|
|
42
|
+
client = BrowserClient(client_hash, authentication_session_id)
|
|
43
|
+
authenticators = client.identify_as_user_and_get_available_authenticators("username")
|
|
44
|
+
client.authenticate_with_app() # approve in the MitID app
|
|
45
|
+
code = client.finalize_authentication_and_get_authorization_code()
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`client_hash` and `authentication_session_id` come from the service's NemLog-in page;
|
|
49
|
+
`get_authentication_code` does all of the above from that page's parameters.
|
|
50
|
+
|
|
51
|
+
It is used by [aula_connect](https://github.com/HairingX/aula_connect) to log in to Aula.
|
|
52
|
+
|
|
53
|
+
## Origin and licence
|
|
54
|
+
|
|
55
|
+
It carries on MitID-BrowserClient by Hundter, under the MIT licence (`LICENSE`).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# mitid_connect
|
|
2
|
+
|
|
3
|
+
Log in through [MitID](https://www.mitid.dk) from Python: an unofficial implementation of MitID's
|
|
4
|
+
browser client. It authenticates with the MitID app - by QR code or one-time code - or with a
|
|
5
|
+
code token, and gives back the authorization code that the service being logged in to exchanges
|
|
6
|
+
for its own tokens.
|
|
7
|
+
|
|
8
|
+
```python
|
|
9
|
+
from mitid_connect import BrowserClient
|
|
10
|
+
|
|
11
|
+
client = BrowserClient(client_hash, authentication_session_id)
|
|
12
|
+
authenticators = client.identify_as_user_and_get_available_authenticators("username")
|
|
13
|
+
client.authenticate_with_app() # approve in the MitID app
|
|
14
|
+
code = client.finalize_authentication_and_get_authorization_code()
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`client_hash` and `authentication_session_id` come from the service's NemLog-in page;
|
|
18
|
+
`get_authentication_code` does all of the above from that page's parameters.
|
|
19
|
+
|
|
20
|
+
It is used by [aula_connect](https://github.com/HairingX/aula_connect) to log in to Aula.
|
|
21
|
+
|
|
22
|
+
## Origin and licence
|
|
23
|
+
|
|
24
|
+
It carries on MitID-BrowserClient by Hundter, under the MIT licence (`LICENSE`).
|