gh_UserManager/apps/web/app/developers/page.tsx
bermooda-company 54d5891edf user
2026-08-23 23:59:14 +03:30

188 lines
9.1 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* eslint-disable */
import React, { useState, useEffect } from "react"
const SDK_SCRIPT_SNIPPET = `<script src="https://account.hamsoo.me/sdk/identity-widget.js"></script>`
const SIGNIN_ROOT_SNIPPET = `<div id="hamsoo-signin-root"></div>`
const INIT_SNIPPET = `HamsooID.init({
client_id: "your-client-id",
redirect_uri: "https://your-site.com/callback",
scope: "openid profile email",
response_mode: "web_message", // برای پاپ‌آپ موبایلی
onSuccess: ({ code, state }) => {
// Exchange code for tokens at: POST /oauth/token
console.log("Authorization code:", code, "State:", state)
},
onError: (err) => {
console.error("Sign in error:", err)
},
})`
const TOKEN_EXCHANGE_SNIPPET = `import requests
resp = requests.post(
"https://account.hamsoo.me/oauth/token",
data={
"grant_type": "authorization_code",
"code": "<code-from-onSuccess>",
"redirect_uri": "https://your-site.com/callback",
"client_id": "your-client-id",
"client_secret": "<client-secret-from-dashboard>",
},
)
tokens = resp.json()
print(tokens["access_token"])`
export default function DevelopersPage() {
const [sdkLoaded, setSdkLoaded] = useState(false)
useEffect(() => {
const script = document.createElement("script")
script.src = "/sdk/identity-widget.js"
script.async = true
script.onload = () => setSdkLoaded(true)
script.onerror = () => console.error("Failed to load Hamsoo SDK")
document.head.appendChild(script)
}, [])
return (
<section className="py-12 bg-gray-50 dark:bg-gray-900">
<div className="max-w-5xl mx-auto px-4">
<h2 className="text-3xl font-bold text-[#1f2733] mb-8 text-center">
مستندات توسعهدهندگان / Developer Documentation
</h2>
<div className="mb-12">
<h3 className="text-xl font-semibold text-[#2f6df6] mb-4">۵ دقیقه شروع کنید / Quickstart</h3>
<ol className="list-decimal list-inside space-y-3 max-w-xl mx-auto text-[#1f2733]">
<li>
<strong>1. ثبت اپلیکیشن:</strong> در داشبورد هوامله (https://account.hamsoo.me) یک application ثبت کنید. <code>client_id</code> و <code>redirect_uris</code> را ثبت کنید. گام scopes: <code>openid profile email phone</code>.
</li>
<li>
<strong>2. SDK را اضافه کنید:</strong> کد زیر را در هدر یا انتهای <code>body</code> سایت خود قرار دهید:
<pre className="bg-[#f4f6fb] p-3 rounded text-sm overflow-x-auto"><code className="language-html">{SDK_SCRIPT_SNIPPET}</code></pre>
</li>
<li>
<strong>3. دکمه را جایگذاری کنید:</strong>
<pre className="bg-[#f4f6fb] p-3 rounded text-sm"><code className="language-html">{SIGNIN_ROOT_SNIPPET}</code></pre>
<pre className="bg-[#f4f6fb] p-3 rounded text-sm mt-2"><code className="language-javascript">{INIT_SNIPPET}</code></pre>
</li>
<li>
<strong>4. backend: تبادل code برای توکن:</strong>
<pre className="bg-[#f4f6fb] p-3 rounded text-sm mt-2"><code className="language-python">{TOKEN_EXCHANGE_SNIPPET}</code></pre>
</li>
</ol>
</div>
<div className="mb-12">
<h3 className="text-xl font-semibold text-[#2f6df6] mb-4">مرجع SDK / SDK Reference</h3>
<table className="w-full text-sm border-collapse border-border mt-4">
<thead>
<tr className="border-b border-border">
<th className="text-left p-2">روش / Method</th>
<th className="text-left p-2">توضیحات / Description</th>
</tr>
</thead>
<tbody>
<tr className="hover:bg-[#f0f4f8]">
<td className="p-2 font-medium">HamsooID.init({"{ options }"})</td>
<td className="p-2">ابزار SDK را مقداردهی و دکمه را render میکند</td>
</tr>
<tr className="hover:bg-[#f0f4f8]">
<td className="p-2 font-medium">onSuccess({"{ code, state }"})</td>
<td className="p-2">وقتی کاربر با موفقیت احراز هویت میشود، این تابع صدا زده میشود</td>
</tr>
<tr className="hover:bg-[#f0f4f8]">
<td className="p-2 font-medium">onError({"{ error }"})</td>
<td className="p-2">وقتی احراز هویت شکست خورد، این تابع صدا زده میشود</td>
</tr>
</tbody>
</table>
</div>
<div>
<h3 className="text-xl font-semibold text-[#2f6df6] mb-4">ارائهدهنده API / API Endpoints</h3>
<p className="text-[#6b7280] mb-6">
تمام endpoints روی دامنه <code>account.hamsoo.me</code> قابل دسترسی هستند.
</p>
<table className="w-full text-sm border-collapse border-border">
<thead>
<tr className="border-b border-border">
<th className="text-left p-2">Endpoint</th>
<th className="text-left p-2">روش / Method</th>
<th className="text-left p-2">توضیحات / Description</th>
</tr>
</thead>
<tbody>
<tr className="hover:bg-[#f0f4f8]">
<td className="p-2">GET /.well-known/openid-configuration</td>
<td className="p-2">GET</td>
<td className="p-2">OpenID Discovery document</td>
</tr>
<tr className="hover:bg-[#f0f4f8]">
<td className="p-2">GET /oauth/jwks</td>
<td className="p-2">GET</td>
<td className="p-2">JSON Web Key Set for JWT verification</td>
</tr>
<tr className="hover:bg-[#f0f4f8]">
<td className="p-2">GET /oauth/authorize</td>
<td className="p-2">GET/POST</td>
<td className="p-2">Authorization endpoint (PKCE + consent)</td>
</tr>
<tr className="hover:bg-[#f0f4f8]">
<td className="p-2">POST /oauth/token</td>
<td className="p-2">POST</td>
<td className="p-2">Exchange code for tokens (PKCE)</td>
</tr>
<tr className="hover:bg-[#f0f4f8]">
<td className="p-2">GET /oauth/userinfo</td>
<td className="p-2">GET</td>
<td className="p-2">User claims (scope-dependent)</td>
</tr>
<tr className="hover:bg-[#f0f4f8]">
<td className="p-2">GET /sso/login</td>
<td className="p-2">GET</td>
<td className="p-2">Central SSO login page (account chooser + MFA + Passkey)</td>
</tr>
<tr className="hover:bg-[#f0f4f8]">
<td className="p-2">POST /api/v1/security/pow/challenge</td>
<td className="p-2">POST</td>
<td className="p-2">Self-hosted proof-of-work challenge (anti-bot)</td>
</tr>
</tbody>
</table>
</div>
<div>
<h3 className="text-xl font-semibold text-[#2f6df6] mb-4">مباحث امنیتی / Security Best Practices</h3>
<ul className="list-disc list-inside text-[#1f2733] space-y-2">
<li>
<strong>حتماً PKCE استفاده کنید:</strong> هر JWT Authorization Request باید شامل code verifier و challenge باشد.
</li>
<li>
<strong>پارامتر state را ولید کنید:</strong> همیشه پاسخ state را با درخواست اصلی مقایسه کنید.
</li>
<li>
<strong>redirect_uri را تأیید کنید:</strong> redirect_uri ثبتشده است و با redirect_uris اپلیکیشن تطابق دارد.
</li>
<li>
<strong>response_mode=web_message برای پاپآپها استفاده کنید:</strong> این روش redirect صفحه کامل را حذف میکند و تجربه modal ایجاد میکند.
</li>
<li>
<strong>Self-hosted PoW برای لاگین:</strong> هر درخواست لاگین باید challenge را حل کند (سبک ALTCHA) که فعالیت bot را کاهش میدهد.
</li>
</ul>
</div>
<div>
<h3 className="text-xl font-semibold text-[#2f6df6] mb-4">مدیریت اپلیکیشن / App Management</h3>
<p className="text-[#6b7280] mb-6">
اپلیکیشنهای خود را در پورتال مدیریت کنید:{" "}
<a href="https://account.hamsoo.me/admin/applications" className="underline text-[#2f6df6]" target="_blank" rel="noreferrer">
account.hamsoo.me/admin/applications
</a>
</p>
</div>
</div>
</section>
)
}