-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathgithub-token-validator-github.html
More file actions
171 lines (152 loc) · 9.29 KB
/
Copy pathgithub-token-validator-github.html
File metadata and controls
171 lines (152 loc) · 9.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GitHub Token Validator Modern | One File Tools</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
darkMode: "media",
theme: {
extend: {
colors: {
github: { dark: "#0d1117", border: "#30363d", primary: "#238636", hover: "#2ea043" }
}
}
}
};
</script>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}
.spinner {
animation: spin 1s linear infinite;
}
@keyframes spin {
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body class="bg-gray-50 text-gray-900 dark:bg-github-dark dark:text-gray-100 min-h-screen flex items-center justify-center p-4 transition-colors duration-200">
<div class="w-full max-w-lg bg-white dark:bg-[#161b22] border border-gray-200 dark:border-github-border rounded-xl shadow-lg overflow-hidden">
<div class="p-6 border-b border-gray-200 dark:border-github-border text-center">
<svg class="mx-auto h-12 w-12 text-gray-800 dark:text-white mb-3" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" /></svg>
<h1 class="text-xl font-bold">GitHub Token Validator</h1>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Securely check your Personal Access Token</p>
</div>
<div class="p-6">
<form id="tokenForm" class="space-y-4">
<div>
<label for="tokenInput" class="block text-sm font-medium mb-1">Personal Access Token</label>
<div class="relative">
<input type="password" id="tokenInput" placeholder="ghp_xxxxxxxxxxxx" required autocomplete="off" class="w-full bg-gray-50 dark:bg-[#010409] border border-gray-300 dark:border-github-border rounded-md px-4 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors" />
<button type="button" id="toggleVisibility" class="absolute inset-y-0 right-0 pr-3 flex items-center text-sm font-medium text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">Show</button>
</div>
</div>
<button type="submit" id="submitBtn" class="w-full bg-github-primary hover:bg-github-hover text-white font-semibold py-2.5 rounded-md transition-colors flex items-center justify-center gap-2">
<span>Validate Token</span>
<svg id="loadingIcon" class="spinner h-4 w-4 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" /></svg>
</button>
</form>
<div id="resultCard" class="hidden mt-6 bg-gray-50 dark:bg-[#0d1117] border border-gray-200 dark:border-github-border rounded-md p-4">
<div id="statusHeader" class="flex items-center gap-2 mb-3 pb-2 border-b border-gray-200 dark:border-github-border"></div>
<div id="userDetails" class="hidden space-y-2 text-sm">
<div class="flex items-center gap-3">
<img id="userAvatar" src="" alt="Avatar" class="w-10 h-10 rounded-full border border-gray-300 dark:border-github-border" />
<div>
<p id="userName" class="font-bold text-gray-900 dark:text-white"></p>
<a id="userLogin" href="#" target="_blank" class="text-blue-500 hover:underline"></a>
</div>
</div>
<div class="pt-2 grid grid-cols-2 gap-2 text-xs">
<div class="bg-gray-100 dark:bg-[#161b22] p-2 rounded border border-gray-200 dark:border-github-border">
<span class="block text-gray-500 dark:text-gray-400 mb-1">Scopes</span>
<span id="tokenScopes" class="font-mono text-blue-600 dark:text-blue-400 break-words"></span>
</div>
<div class="bg-gray-100 dark:bg-[#161b22] p-2 rounded border border-gray-200 dark:border-github-border">
<span class="block text-gray-500 dark:text-gray-400 mb-1">Type</span>
<span id="tokenType" class="font-mono text-green-600 dark:text-green-400">Personal Access Token</span>
</div>
</div>
</div>
<p id="errorMessage" class="hidden text-sm text-red-600 dark:text-red-400 font-medium"></p>
</div>
</div>
</div>
<script>
const form = document.getElementById("tokenForm");
const tokenInput = document.getElementById("tokenInput");
const toggleVisibility = document.getElementById("toggleVisibility");
const submitBtn = document.getElementById("submitBtn");
const loadingIcon = document.getElementById("loadingIcon");
const resultCard = document.getElementById("resultCard");
const statusHeader = document.getElementById("statusHeader");
const userDetails = document.getElementById("userDetails");
const errorMessage = document.getElementById("errorMessage");
// Toggle Password Visibility
toggleVisibility.addEventListener("click", () => {
const type = tokenInput.getAttribute("type") === "password" ? "text" : "password";
tokenInput.setAttribute("type", type);
toggleVisibility.textContent = type === "password" ? "Show" : "Hide";
});
const resetUI = () => {
resultCard.classList.add("hidden");
userDetails.classList.add("hidden");
errorMessage.classList.add("hidden");
submitBtn.disabled = true;
submitBtn.classList.add("opacity-75", "cursor-not-allowed");
loadingIcon.classList.remove("hidden");
};
const showSuccess = (user, scopes) => {
loadingIcon.classList.add("hidden");
submitBtn.disabled = false;
submitBtn.classList.remove("opacity-75", "cursor-not-allowed");
resultCard.classList.remove("hidden");
userDetails.classList.remove("hidden");
statusHeader.innerHTML = `<svg class="w-5 h-5 text-green-500" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg><span class="font-bold text-green-600 dark:text-green-400 text-sm">Token is Valid</span>`;
document.getElementById("userAvatar").src = user.avatar_url;
document.getElementById("userName").textContent = user.name || user.login;
document.getElementById("userLogin").textContent = `@${user.login}`;
document.getElementById("userLogin").href = user.html_url;
const scopeText = scopes ? scopes : "No scopes defined (Read-only)";
document.getElementById("tokenScopes").textContent = scopeText;
};
const showError = (message) => {
loadingIcon.classList.add("hidden");
submitBtn.disabled = false;
submitBtn.classList.remove("opacity-75", "cursor-not-allowed");
resultCard.classList.remove("hidden");
errorMessage.classList.remove("hidden");
statusHeader.innerHTML = `<svg class="w-5 h-5 text-red-500" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/></svg><span class="font-bold text-red-600 dark:text-red-400 text-sm">Validation Failed</span>`;
errorMessage.textContent = message;
};
form.addEventListener("submit", async (e) => {
e.preventDefault();
const token = tokenInput.value.trim();
if (!token) return;
resetUI();
try {
const response = await fetch("https://api.github.com/user", {
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28"
}
});
if (!response.ok) {
throw new Error(response.status === 401 ? "Invalid Token: Bad credentials" : `Error: ${response.status} ${response.statusText}`);
}
const scopes = response.headers.get("x-oauth-scopes");
const userData = await response.json();
showSuccess(userData, scopes);
} catch (error) {
showError(error.message);
}
});
</script>
</body>
</html>