# احراز هویت

## پروژهٔ اولیه
فایل پروژه را میتوانید از طریق این [این لینک](/contest/assignments/85280/download_problem_initial_project/291494/) دانلود کنید.
ساختار پروژه به شکل زیر است:
```plaintext
initital_project/
├─ css/
│ └─ styles.css
├─ app.js
├─ dashboard.html
├─ index.html
├─ login.html
└─ register.html
```
## جزئیات پیادهسازی
### اقدامات لازم برای `app.js`
1. همانطور که مشاهده میکنید، در ابتدای فایل کامنتی با عنوان `Validation` و در پایین آن تابعی با نام `isAuthentication` وجود دارد که شما باید آن را طوری کامل کنید که بررسی کند کاربر احراز هویت (authentication) را انجام داده است یا خیر.
پس باید مقداری را بر اساس مقادیر موجود در لوکالاستورج به ما برگرداند.
### تابع `registerUser`:
1. ورودی این تابع یک آبجکت به نام `user` است که باید دارای سه مقدار باشد: `username`، `password` و `role`.
2. این تابع یک Promise برمیگرداند که ممکن است با موفقیت اجرا شود (resolve) یا با خطا مواجه شود (reject)، بنابراین هر دو حالت باید در نظر گرفته شوند.
3. در تابع، مقدار `username` را پاکسازی و استاندارد میکنیم تا مقایسهای دقیق و یکسان برای بررسی تکراری بودن انجام شود.
4. سپس لیست کاربران موجود از `localStorage` خوانده میشود و در آرایهای به نام `users` قرار میگیرد. اگر مقدار موجود در `localStorage` آرایه نبود یا خطایی رخ داد، آرایه خالی در نظر گرفته میشود.
5. بررسی میشود که آیا کاربری با همین `username` (پس از پاکسازی) قبلاً ثبت شده یا خیر. اگر چنین کاربری وجود داشت، عملیات با پیام زیر رد میشود:
**"این نام کاربری قبلاً ثبت شده. لطفاً نام دیگری انتخاب کنید."**
6. اگر نام کاربری تکراری نبود، اطلاعات کاربر جدید (شامل `username`، `password` و `role`) به آرایه `users` اضافه میشود.
7. سپس آرایه بهروزرسانیشده دوباره در `localStorage` ذخیره میشود. در صورتی که عملیات ذخیرهسازی با خطا مواجه شود، تابع با پیام زیر رد میشود:
**"خطا در ذخیرهسازی. دوباره تلاش کنید."**
8. در نهایت، اگر همه مراحل با موفقیت انجام شد، Promise با موفقیت (resolve) پایان مییابد.


### تابع `loginUser`
1. ورودی تابع یک آبجکت به نام `creds` است که شامل مقادیر `username` و `password` از `loginForm` میباشد.
2. خروجی تابع، یک پرامیس است که در صورت موفقیت، آبجکتی شامل سه مقدار `accessToken`، `refreshToken` و `role` را بازمیگرداند. این مقادیر باید در `localStorage` ذخیره شوند.
3. مانند تابع ثبتنام (`registerUser`)، در ابتدا باید `username` را پالایش کنید (حذف فاصلهها و تبدیل به حروف کوچک). سپس لیست کاربران (`users`) از `localStorage` خوانده میشود. در صورت بروز خطا یا نبود لیست معتبر، یک آرایه خالی جایگزین میشود.
4. سپس بررسی میکنید که آیا کاربری با `username` برابر و `password` منطبق وجود دارد یا خیر. اگر چنین کاربری یافت نشد، `reject` با پیام زیر صدا زده میشود و تابع خاتمه مییابد:
**"نام کاربری یا رمز عبور اشتباه است."**
5. در صورت تطابق اطلاعات، باید مقادیر `accessToken` و `refreshToken` را با این فرمت تولید کنید:
```js
const accessToken = "access-" + Date.now() + "-" + Math.random().toString(36).substr(2);
const refreshToken = "refresh-" + Date.now() + "-" + Math.random().toString(36).substr(2);
```
6. سپس این مقادیر به همراه `role` کاربر، در `localStorage` ذخیره میشوند.
7. مرحله ۶ باید در یک بلوک `try/catch` انجام شود. در صورت بروز خطا هنگام ذخیرهسازی، تابع با `reject` و پیام زیر خاتمه مییابد:
**"خطا در فرآیند ورود. دوباره تلاش کنید."**
8. در نهایت، اگر تمام مراحل با موفقیت انجام شود، `resolve` فراخوانی میشود و آبجکت زیر بازگردانده میشود:
```js
{ accessToken, refreshToken, role: found.role }
```


### رویداد سابمیت برای LoginForm
1. ابتدا باید از رفتار پیشفرض فرم جلوگیری شود تا از بارگذاری مجدد صفحه جلوگیری شود.
2. مقادیر ورودی مربوط به نام کاربری (`loginUsername`) و رمز عبور (`loginPassword`) از عناصر HTML دریافت میشوند.
3. بررسی میشود که هر دو فیلد مقدار داشته باشند. در صورتی که یکی از آنها خالی باشد، پیام خطای «لطفاً همهٔ فیلدها را کامل کنید.» با استفاده از تابع `showToast` نمایش داده شده و ادامهی اجرای تابع متوقف میشود.
4. اگر هر دو فیلد مقدار داشته باشند، یک شیء شامل `username` و `password` ساخته شده و به تابع `loginUser` ارسال میشود.
5. در صورتی که عملیات ورود موفقیتآمیز باشد، پیام «ورود با موفقیت انجام شد!» با استفاده از `showToast` نمایش داده میشود و پس از گذشت یک ثانیه کاربر به صفحهی `dashboard.html` هدایت میشود.
6. اگر عملیات ورود با شکست مواجه شود، پیام خطای مربوطه از طریق `showToast(err, "error")` نمایش داده میشود.
### رویداد سابمیت برای RegisterForm
فرایند ثبتنام بسیار مشابه ورود است با تفاوتهایی جزئی:
1. مقدارهای نام کاربری (`registerUsername`)، رمز عبور (`registerPassword`) و نقش (`role`) از عناصر HTML گرفته میشوند.
2. بررسی میشود که هر سه فیلد مقدار داشته باشند. در غیر این صورت، پیام «لطفاً همهٔ فیلدها را کامل کنید.» نمایش داده شده و روند ارسال متوقف میشود.
3. اگر فیلدها کامل باشند، یک شیء شامل `username`، `password` و `role` ساخته میشود و به تابع `registerUser` ارسال میگردد.
4. در صورت موفقیت، پیام «ثبتنام با موفقیت انجام شد!» نمایش داده شده و پس از یک ثانیه کاربر به صفحهی `login.html` منتقل میشود.
5. در صورت بروز خطا در ثبتنام، پیام خطا با استفاده از `showToast(err, "error")` نمایش داده خواهد شد.
### بررسی و نمایش محتوای داشبورد (Dashboard)
1. در ابتدا، مقادیر `accessToken`، `refreshToken` و `role` از `localStorage` خوانده میشوند.
2. اگر هر یک از این مقادیر در دسترس نباشند، یعنی کاربر احراز هویت نشده یا اطلاعات ناقص است، کاربر باید به صفحهی اصلی (`index.html`) هدایت شود.
3. اگر مقادیر مورد نیاز وجود داشته باشند، بسته به مقدار `role`، محتوای مناسب برای داشبورد انتخاب و در عنصر `dashboard-content` نمایش داده میشود:
+ در صورتی که مقدار نقش `admin` باشد، محتوای مدیریتی (`adminContent`) نمایش داده میشود.
+ در غیر این صورت، محتوای مخصوص کاربر عادی (`userContent`) قرار داده خواهد شد.
4. پس از نمایش محتوای مناسب، عنصر مربوط به دکمه خروج با شناسه `logout-btn` پیدا میشود. در صورتی که وجود داشته باشد، یک رویداد کلیک برای آن تعریف میشود که هنگام کلیک:
+ مقادیر `accessToken`، `refreshToken` و `role` را از `localStorage` حذف میکند.
+ سپس کاربر را به صفحهی اصلی (`index.html`) بازمیگرداند.



### کنترل مسیرهای دسترسی بر اساس وضعیت احراز هویت
برای هدایت صحیح کاربر به صفحات مجاز، بر اساس مسیر فعلی و وضعیت احراز هویت، شرایط زیر بررسی میشود:
1. اگر کاربر در مسیر `dashboard.html` باشد ولی احراز هویت نشده باشد، باید به صفحهی `login.html` منتقل شود.
2. اگر کاربر در صفحهی `login.html` یا `register.html` باشد ولی قبلاً احراز هویت شده باشد، باید مستقیماً به صفحهی `dashboard.html` منتقل شود.
3. اگر کاربر در صفحهی اصلی (`index.html` یا ریشه `/`) باشد:
+ در صورت احراز هویت، به داشبورد هدایت میشود.
+ در غیر این صورت، به صفحهی ورود (`login.html`) منتقل میشود.
> هدف از این کنترلها، جلوگیری از دسترسی غیرمجاز به بخشهای محافظتشدهی سایت و همچنین جلوگیری از ورود کاربران لاگینشده به صفحات ورود و ثبتنام است. این کار تجربهی کاربری را بهبود میدهد و ساختار امنیتی سمت کلاینت را تقویت میکند.
## نکات پیادهسازی
1. چهار صفحه اچتیامال داریم که به صورت کامل نوشته شدهاند و نیازی نیست که چیزی در آنها بنویسید.
2. همه صفحات به `app.js` متصل هستند.
3. مقادیری که باید در لوکالاستورج ذخیره بشوند :
+ accessToken
+ refreshToken
+ role
4. در ابتدای فایل تابعی مشاهده میکنید به نام showToast که به صورت کامل نوشته شده است و لازم نیست که چیزی را در آن بنوسید و در آیندهی نزدیک باید از آن استفاده بکنید.
5. تمام فرایندها به طور کامل در ویدئوها نشان داده شده است.
6. برای استانداردسازی یوزنیم در واقع باید به حروف و فاصلهها توجه بکنید.
## آنچه باید آپلود بکنید
فایلی که آپلود خواهید کرد باید دارای فرمت **.Zip** باشد و دارای ساختار زیر باشد:
```plaintext
answer/
├─ app.js
```
موفق باشید 🌟