recticode 0.1.0__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.
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.3
2
+ Name: recticode
3
+ Version: 0.1.0
4
+ Summary: Add your description here
5
+ Author: VulcanWM
6
+ Author-email: VulcanWM <vulcanwmemail@gmail.com>
7
+ Requires-Dist: pytest>=9.0.2
8
+ Requires-Dist: requests>=2.32.5
9
+ Requires-Dist: typer>=0.24.1
10
+ Requires-Python: >=3.13
11
+ Description-Content-Type: text/markdown
12
+
13
+ # Recticode
14
+
15
+ It's cool
@@ -0,0 +1,3 @@
1
+ # Recticode
2
+
3
+ It's cool
@@ -0,0 +1,21 @@
1
+ [project]
2
+ name = "recticode"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "VulcanWM", email = "vulcanwmemail@gmail.com" }
8
+ ]
9
+ requires-python = ">=3.13"
10
+ dependencies = [
11
+ "pytest>=9.0.2",
12
+ "requests>=2.32.5",
13
+ "typer>=0.24.1",
14
+ ]
15
+
16
+ [project.scripts]
17
+ recticode = "recticode.main:app"
18
+
19
+ [build-system]
20
+ requires = ["uv_build>=0.10.11,<0.11.0"]
21
+ build-backend = "uv_build"
@@ -0,0 +1,2 @@
1
+ def main() -> None:
2
+ print("Hello from recticode!")
@@ -0,0 +1,91 @@
1
+ import subprocess
2
+ import os
3
+ import json
4
+ import requests
5
+
6
+ def get_user_code():
7
+ url = "https://github.com/login/device/code"
8
+
9
+ values = {
10
+ "client_id": "Ov23lizX5wFSpnR89gKJ",
11
+ "scope": "read:user repo"
12
+ }
13
+
14
+ headers = {
15
+ "Accept": "application/json"
16
+ }
17
+
18
+ r = requests.post(url, data=values, headers=headers)
19
+
20
+ r_json = r.json()
21
+
22
+ device_code = r_json["device_code"]
23
+ verification_uri = r_json['verification_uri']
24
+ expires_in = r_json['expires_in']
25
+ user_code = r_json['user_code']
26
+ interval = r_json['interval']
27
+
28
+ return device_code, verification_uri, expires_in, user_code, interval
29
+
30
+ def get_access_token():
31
+ try:
32
+ config_dir = os.path.expanduser("~/.config/recticode")
33
+ os.makedirs(config_dir, exist_ok=True)
34
+
35
+ token_path = os.path.join(config_dir, "token.json")
36
+ with open(token_path) as f:
37
+ token = json.load(f)["access_token"]
38
+ return token
39
+ except:
40
+ return False
41
+
42
+
43
+ def save_access_token(access_token):
44
+ try:
45
+ config_dir = os.path.expanduser("~/.config/recticode")
46
+ os.makedirs(config_dir, exist_ok=True)
47
+
48
+ token_path = os.path.join(config_dir, "token.json")
49
+
50
+ data = {"access_token": access_token}
51
+
52
+ with open(token_path, "w") as f:
53
+ json.dump(data, f)
54
+
55
+ return True
56
+ except:
57
+ return False
58
+
59
+
60
+ def clone_repo(url):
61
+ cmd = ["git", "clone", url]
62
+ subprocess.run(cmd, check=True)
63
+ return True
64
+
65
+ def get_user_data(access_token):
66
+ check_headers = {
67
+ "Authorization": f"Bearer {access_token}",
68
+ "Accept": "application/vnd.github+json"
69
+ }
70
+
71
+ check_post = requests.get("https://api.github.com/user", headers=check_headers)
72
+
73
+ user_json = check_post.json()
74
+ username = user_json['login']
75
+ email = user_json['email']
76
+ name = user_json['name']
77
+
78
+ return username, email, name
79
+
80
+ def remove_access_token():
81
+ try:
82
+ config_dir = os.path.expanduser("~/.config/recticode")
83
+ os.makedirs(config_dir, exist_ok=True)
84
+
85
+ token_path = os.path.join(config_dir, "token.json")
86
+
87
+ os.remove(token_path)
88
+
89
+ return True
90
+ except:
91
+ return False
@@ -0,0 +1,136 @@
1
+ import typer
2
+ from rich import print
3
+ from functools import wraps
4
+ from time import sleep
5
+ from recticode.git_code import clone_repo, save_access_token, get_access_token, get_user_data, remove_access_token, get_user_code
6
+ import requests
7
+ import os.path
8
+ import subprocess
9
+ import sys
10
+
11
+ app = typer.Typer()
12
+
13
+ def require_login(func):
14
+ @wraps(func)
15
+ def wrapper(*args, **kwargs):
16
+ access_token = get_access_token()
17
+ if not access_token:
18
+ print("[red]You must login first[/red]")
19
+ raise typer.Exit()
20
+ return func(*args, **kwargs)
21
+ return wrapper
22
+
23
+ @app.command()
24
+ def login():
25
+ access_token = get_access_token()
26
+ if not access_token:
27
+ headers = {
28
+ "Accept": "application/json"
29
+ }
30
+
31
+ device_code, verification_uri, expires_in, user_code, interval = get_user_code()
32
+
33
+ print(f"Go to {verification_uri} and enter code [bold]{user_code}[/bold]")
34
+
35
+ for i in range(expires_in // interval):
36
+ poll_values = {
37
+ "client_id": "Ov23lizX5wFSpnR89gKJ",
38
+ "device_code": device_code,
39
+ "grant_type": "urn:ietf:params:oauth:grant-type:device_code"
40
+ }
41
+ poll_post = requests.post("https://github.com/login/oauth/access_token", data=poll_values, headers=headers)
42
+
43
+ poll_json = poll_post.json()
44
+
45
+ if "access_token" in poll_json:
46
+ access_token = poll_json['access_token']
47
+
48
+ username, email, name = get_user_data(access_token=access_token)
49
+
50
+ save_access_token(access_token=access_token)
51
+ print(f"[green]✓ Logged in as {name}[/green]")
52
+ break
53
+
54
+ if "error" in poll_json:
55
+ if poll_json["error"] == "authorization_pending":
56
+ sleep(interval)
57
+ continue
58
+ elif poll_json["error"] == "slow_down":
59
+ interval += 5
60
+ sleep(interval)
61
+ elif poll_json["error"] == "expired_token":
62
+ print("[red]Device code expired, try login again[/red]")
63
+ break
64
+ else:
65
+ username, email, name = get_user_data(access_token=access_token)
66
+
67
+ print("You are already logged in")
68
+
69
+ @app.command()
70
+ @require_login
71
+ def whoami():
72
+ access_token = get_access_token()
73
+ username, email, name = get_user_data(access_token=access_token)
74
+ print("Hi", name)
75
+
76
+ @app.command()
77
+ def logout():
78
+ access_token = get_access_token()
79
+ if not access_token:
80
+ print("You are not logged in")
81
+ else:
82
+ remove_access_token()
83
+
84
+ print("[yellow]✓ Logged out[/yellow]")
85
+
86
+
87
+ @app.command()
88
+ @require_login
89
+ def start(challenge_name):
90
+ access_token = get_access_token()
91
+
92
+ request_url = "https://api.recticode.com/challenge_repo/"
93
+
94
+ response = requests.get(request_url + challenge_name + "?token=" + access_token)
95
+ if response.status_code == 200:
96
+ if "error" in response.json():
97
+ print(response.json()['error'])
98
+ else:
99
+ clone_repo(response.json()['repo_name'])
100
+ print(f"[green]Challenge cloned![/green] cd {challenge_name} to start")
101
+ else:
102
+ print("Error occurred")
103
+
104
+ @app.command()
105
+ @require_login
106
+ def list_challenges():
107
+ access_token = get_access_token()
108
+
109
+ request_url = "https://api.recticode.com/list_challenges?token=" + access_token
110
+
111
+ response = requests.get(request_url)
112
+ if response.status_code == 200:
113
+ challenges = response.json()['challenges']
114
+
115
+ print("[bold][yellow]All Challenges[/yellow][/bold]")
116
+ for challenge in challenges:
117
+ print(f"[bold]{challenge['name']}[/bold]: {challenge['description']} ({challenge['language']})")
118
+ else:
119
+ print("Error occurred")
120
+
121
+ @app.command()
122
+ @require_login
123
+ def check():
124
+ if os.path.exists("challenge.json"):
125
+ env = os.environ.copy()
126
+ env["PYTHONPATH"] = "."
127
+ subprocess.run(
128
+ [sys.executable, "-m", "pytest", "tests/"],
129
+ env=env
130
+ )
131
+ else:
132
+ print("This is not a valid challenge")
133
+
134
+
135
+ if __name__ == "__main__":
136
+ app()