এক নজরে
পাসকী রেজিস্ট্রেশনের সাথে যুক্ত মূল ধাপগুলির হাই-লেভেল ওভারভিউ এখানে দেওয়া হল:

- পাসকী তৈরি করার বিকল্পগুলি উল্লেখ করুন। সেগুলি ক্লায়েন্টকে পাঠান, যাতে আপনি সেগুলি আপনার পাসকী তৈরি করার কলে পাস করতে পারেন: ওয়েবে WebAuthn API কল
navigator.credentials.createএবং Android-এcredentialManager.createCredential। ব্যবহারকারী পাসকী তৈরি করার বিষয়টি কনফার্ম করার পরে, পাসকী তৈরি করার কলটি সমাধান করা হয় এবং একটি ক্রেডেনশিয়ালPublicKeyCredentialফিরিয়ে দেয়। - ক্রেডেনশিয়াল যাচাই করে সার্ভারে স্টোর করা।
নিম্নলিখিত বিভাগগুলি প্রতিটি ধাপের নির্দিষ্ট বিবরণ দেয়।
ক্রেডেনশিয়াল তৈরি করার বিকল্প তৈরি করুন
সার্ভারে আপনাকে প্রথমে একটি PublicKeyCredentialCreationOptions অবজেক্ট তৈরি করতে হবে।
এটি করতে, আপনার FIDO সার্ভার-সাইড লাইব্রেরির উপর নির্ভর করুন। এটি সাধারণত একটি ইউটিলিটি ফাংশন অফার করবে যা আপনার জন্য এই বিকল্পগুলি তৈরি করতে পারে। SimpleWebAuthn, উদাহরণস্বরূপ, generateRegistrationOptions অফার করে।
PublicKeyCredentialCreationOptions-এ পাসকী তৈরি করার জন্য প্রয়োজনীয় সবকিছু অন্তর্ভুক্ত থাকতে হবে: ব্যবহারকারী সম্পর্কে তথ্য, RP সম্পর্কে তথ্য এবং আপনি যে ক্রেডেনশিয়াল তৈরি করছেন তার প্রপার্টির জন্য কনফিগারেশন। আপনি এই সবকটি সংজ্ঞায়িত করার পরে, আপনার FIDO সার্ভার-সাইড লাইব্রেরিতে ফাংশনে প্রয়োজন অনুযায়ী সেগুলি পাস করুন যা PublicKeyCredentialCreationOptions অবজেক্ট তৈরি করার জন্য দায়ী।
PublicKeyCredentialCreationOptions-এর কিছু ফিল্ড কনস্ট্যান্ট হতে পারে। অন্যান্যগুলি সার্ভারে ডায়নামিকভাবে সংজ্ঞায়িত করা উচিত:
rpId: সার্ভারে RP আইডি পপুলেট করতে, সার্ভার-সাইড ফাংশন বা ভেরিয়েবল ব্যবহার করুন যা আপনাকে ওয়েব অ্যাপ্লিকেশনের হোস্টনেম দেয়, যেমনexample.com।user.nameএবংuser.displayName: এই ফিল্ডগুলি পূরণ করতে, আপনার সাইন-ইন করা ব্যবহারকারীর সেশন তথ্য (অথবা নতুন ব্যবহারকারীর অ্যাকাউন্ট তথ্য, যদি ব্যবহারকারী সাইন-আপ করার সময় পাসকী তৈরি করেন) ব্যবহার করুন।user.nameসাধারণত একটি ইমেল আইডি এবং RP-এর জন্য অনন্য।user.displayNameহল সহজে ব্যবহার করার নাম। মনে রাখবেন, সব প্ল্যাটফর্মdisplayNameব্যবহার করবে না।user.id: অ্যাকাউন্ট তৈরি করার সময় জেনারেট করা একটি র্যান্ডম, অনন্য স্ট্রিং। এটি স্থায়ী হতে হবে, ইউজারনেমের মতো নয় যা এডিট করা যেতে পারে। ব্যবহারকারীর আইডি কোনও অ্যাকাউন্ট শনাক্ত করে, তবে এতে ব্যক্তিগতভাবে শনাক্তকরণযোগ্য তথ্য (PII) থাকা উচিত নয়। আপনার সিস্টেমে আগে থেকেই ব্যবহারকারীর আইডি থাকার সম্ভাবনা বেশি, তবে প্রয়োজন হলে, পাসকী যাতে কোনও PII থেকে মুক্ত থাকে তার জন্য বিশেষভাবে একটি তৈরি করুন।excludeCredentials: পাসকী প্রদানকারীর থেকে পাসকী ডুপ্লিকেট করা আটকানোর জন্য আগে থেকে থাকা ক্রেডেনশিয়ালের আইডির তালিকা। এই ফিল্ড পূরণ করতে, আপনার ডেটাবেসে এই ব্যবহারকারীর জন্য আগে থেকে থাকা ক্রেডেনশিয়াল দেখুন। আগে থেকে পাসকী থাকলে নতুন পাসকী তৈরি করা আটকান লিঙ্কে গিয়ে বিবরণ পর্যালোচনা করুন।challenge: ক্রেডেনশিয়াল রেজিস্ট্রেশনের জন্য, আপনি অ্যাটেস্টেশন ব্যবহার না করলে চ্যালেঞ্জ প্রাসঙ্গিক নয়, এটি হল পাসকী প্রদানকারীর পরিচয় এবং এটি যে ডেটা নির্গত করে তা যাচাই করার আরও উন্নত টেকনিক। তবে, আপনি অ্যাটেস্টেশন ব্যবহার না করলেও, চ্যালেঞ্জ এখনও একটি প্রয়োজনীয় ফিল্ড। যাচাইকরণের জন্য সুরক্ষিত চ্যালেঞ্জ তৈরি করার নির্দেশাবলী সার্ভার-সাইড পাসকী যাচাইকরণ-এ উপলভ্য।
এনকোডিং ও ডিকোডিং
PublicKeyCredentialCreationOptions সার্ভার থেকে পাঠানো হয়েছে। challenge এবং user.id-এর মতো বাইনারি ফিল্ডগুলি সার্ভার-সাইডে base64URL-এ এনকোড করা হয় যাতে বিকল্পগুলি HTTPS-এর মাধ্যমে JSON হিসাবে ডেলিভার করা যায়।স্ট্যান্ডার্ড WebAuthn PublicKeyCredentialCreationOptions অবজেক্টে এমন ফিল্ড থাকে যা ArrayBuffer, যা সরাসরি JSON.stringify()-এর সাথে সিরিয়ালাইজ করা যায় না। HTTPS-এর মাধ্যমে এইসব বিকল্প পাঠাতে, বাইনারি ফিল্ড অবশ্যই base64URL স্ট্রিং হিসেবে এনকোড করতে হবে:
- সার্ভারে, আপনার FIDO সার্ভার-সাইড লাইব্রেরি (যেমন SimpleWebAuthn) Base64URL-এনকোডেড ফিল্ড সহ অটোমেটিক JSON-সিরিয়ালাইজেবল বিকল্প অবজেক্ট (যেমন
PublicKeyCredentialCreationOptionsJSON) তৈরি করে। - ক্লায়েন্টে, আধুনিক ব্রাউজার
PublicKeyCredential.parseCreationOptionsFromJSON()-কে সাপোর্ট করে যাতে JSON বিকল্প সরাসরিPublicKeyCredentialCreationOptions-এ কনভার্ট করা যায়।@simplewebauthn/browser-এর মতো ক্লায়েন্ট-সাইড লাইব্রেরি ব্যবহার করার সময়,startRegistration({ optionsJSON: options })-এর মতো ফাংশন এই কনভার্সন অটোমেটিক ম্যানেজ করে।
উদাহরণ কোড: ক্রেডেনশিয়াল তৈরি করার বিকল্প তৈরি করুন
আমাদের উদাহরণে আমরা SimpleWebAuthn লাইব্রেরি ব্যবহার করছি। এখানে, আমরা সর্বজনীন কী ক্রেডেনশিয়াল বিকল্প তৈরি করার দায়িত্ব এর generateRegistrationOptions ফাংশনকে দিয়ে দিই।
import {
generateRegistrationOptions,
verifyRegistrationResponse,
} from '@simplewebauthn/server';
import { isoBase64URL, isoUint8Array } from '@simplewebauthn/server/helpers';
router.post('/registerRequest', csrfCheck, sessionCheck, async (req, res) => {
const { user } = res.locals;
// Ensure you nest verification function calls in try/catch blocks.
// If something fails, throw an error with a descriptive error message.
// Return that message with an appropriate error code to the client.
try {
// `excludeCredentials` prevents users from re-registering existing
// credentials for a given passkey provider
const excludeCredentials = [];
const credentials = Credentials.findByUserId(user.id);
if (credentials.length > 0) {
for (const cred of credentials) {
excludeCredentials.push({
id: cred.id,
type: 'public-key',
transports: cred.transports,
});
}
}
// Generate registration options for WebAuthn create
const options = await generateRegistrationOptions({
rpName: process.env.RP_NAME,
rpID: process.env.HOSTNAME,
userID: isoUint8Array.fromUTF8String(user.id),
userName: user.username,
userDisplayName: user.displayName || '',
attestationType: 'none',
excludeCredentials,
authenticatorSelection: {
authenticatorAttachment: 'platform',
residentKey: 'required',
userVerification: 'preferred',
},
});
// Keep the challenge in the session
req.session.challenge = options.challenge;
return res.json(options);
} catch (e) {
console.error(e);
return res.status(400).send({ error: e.message });
}
});
সর্বজনীন কী স্টোর করা
navigator.credentials.create একটি PublicKeyCredential অবজেক্ট রিটার্ন করে।ক্লায়েন্টে navigator.credentials.create সঠিকভাবে সমাধান হলে, তার অর্থ হল পাসকী সঠিকভাবে তৈরি করা হয়েছে। একটি PublicKeyCredential অবজেক্ট রিটার্ন করা হয়।
PublicKeyCredential অবজেক্টে একটি AuthenticatorAttestationResponse অবজেক্ট থাকে, যা পাসকী তৈরি করার জন্য ক্লায়েন্টের নির্দেশ অনুযায়ী পাসকী প্রদানকারীর উত্তরকে দেখায়। এতে নতুন ক্রেডেনশিয়াল সম্পর্কে তথ্য থাকে যা RP হিসেবে পরে ব্যবহারকারীকে যাচাই করার জন্য আপনার প্রয়োজন হয়। পরিশিষ্ট: AuthenticatorAttestationResponse থেকে AuthenticatorAttestationResponse সম্পর্কে আরও জানুন।
সার্ভারে PublicKeyCredential অবজেক্ট পাঠান। এটি পাওয়ার পরে যাচাই করুন।
আপনার FIDO সার্ভার-সাইড লাইব্রেরিতে এই যাচাইকরণ ধাপটি হস্তান্তর করুন। এটি সাধারণত এই উদ্দেশ্যে একটি ইউটিলিটি ফাংশন অফার করবে। SimpleWebAuthn, উদাহরণস্বরূপ, verifyRegistrationResponse অফার করে। পরিশিষ্ট: রেজিস্ট্রেশন উত্তরের যাচাইকরণ থেকে ব্যাকগ্রাউন্ডে কী ঘটছে তা জানুন।
যাচাইকরণ সম্পূর্ণ হয়ে গেলে, আপনার ডেটাবেসে ক্রেডেনশিয়াল সংক্রান্ত তথ্য স্টোর করুন যাতে ব্যবহারকারী পরে সেই ক্রেডেনশিয়ালের সাথে যুক্ত পাসকী দিয়ে যাচাই করতে পারেন।
পাসকী সম্পর্কিত সর্বজনীন কী ক্রেডেনশিয়ালের জন্য একটি নির্দিষ্ট টেবিল ব্যবহার করুন। একজন ব্যবহারকারীর একটিই পাসওয়ার্ড থাকতে পারে, তবে একাধিক পাসকী থাকতে পারে — যেমন, Apple iCloud Keychain-এর মাধ্যমে সিঙ্ক করা একটি পাসকী এবং Google Password Manager-এর মাধ্যমে সিঙ্ক করা আরেকটি পাসকী।
ক্রেডেনশিয়াল সংক্রান্ত তথ্য স্টোর করার জন্য আপনি ব্যবহার করতে পারেন এমন একটি স্কিমার উদাহরণ এখানে দেওয়া হল:

- ব্যবহারকারী টেবিল:
user_id: প্রাইমারি ব্যবহারকারীর আইডি। ব্যবহারকারীর জন্য একটি র্যান্ডম, অনন্য, স্থায়ী আইডি। আপনার ব্যবহারকারী টেবিলের জন্য এটি প্রাথমিক কী হিসেবে ব্যবহার করুন।username. ব্যবহারকারীর নির্ধারণ করা ইউজারনেম, যা এডিট করা যেতে পারে।passkey_user_id: পাসকী-নির্দিষ্ট PII-মুক্ত ব্যবহারকারীর আইডি, যা আপনার রেজিস্ট্রেশন বিকল্পেuser.idদ্বারা দেখানো হয়। ব্যবহারকারী পরে যাচাই করার চেষ্টা করলে, যাচাইকারীuserHandle-এ তার যাচাইকরণ উত্তরে এইpasskey_user_idউপলভ্য করবে। আমরা সাজেস্ট করি যে আপনিpasskey_user_id-কে প্রাথমিক 'কী' হিসেবে সেট করবেন না। প্রাথমিক কীগুলি সিস্টেমে ডি ফ্যাক্টো PII হয়ে ওঠে, কারণ সেগুলি ব্যাপকভাবে ব্যবহৃত হয়।
- সর্বজনীন কী ক্রেডেনশিয়াল টেবিল:
id: ক্রেডেনশিয়াল আইডি। আপনার সর্বজনীন কী ক্রেডেনশিয়াল টেবিলের জন্য এটি প্রাথমিক কী হিসেবে ব্যবহার করুন।public_key: ক্রেডেনশিয়ালের সর্বজনীন কী।passkey_user_id: ব্যবহারকারী টেবিলের সাথে লিঙ্ক তৈরি করতে এটি ফরেন কী হিসেবে ব্যবহার করুন।backed_up: পাসকী প্রদানকারী সিঙ্ক করলে, পাসকী ব্যাক-আপ নেওয়া হয়।backed_upপাসকী আছে এমন ব্যবহারকারীদের জন্য ভবিষ্যতে পাসওয়ার্ড বাদ দেওয়ার কথা বিবেচনা করতে চাইলে, ব্যাক-আপ স্টেট সেভ করা উপযোগী।authenticatorData-এ BE ফ্ল্যাগ পরীক্ষা করে অথবা FIDO সার্ভার-সাইড লাইব্রেরি ফিচার ব্যবহার করে আপনি পাসকী ব্যাক-আপ নেওয়া হয়েছে কিনা তা চেক করতে পারবেন। এই তথ্য যাতে আপনি সহজে অ্যাক্সেস করতে পারেন তার জন্য সাধারণত এই ফিচার উপলভ্য থাকে। ব্যাক-আপের উপযুক্ততা সংক্রান্ত তথ্য সেভ করে রাখলে, ব্যবহারকারীর সম্ভাব্য প্রশ্নের উত্তর দিতে সুবিধা হতে পারে।name: বিকল্প হিসেবে, ক্রেডেনশিয়ালের জন্য একটি ডিসপ্লে নাম, যাতে ব্যবহারকারীরা ক্রেডেনশিয়ালকে কাস্টম নাম দিতে পারেন।transports: ট্রান্সপোর্ট-এর একটি অ্যারে। যাচাইকরণের সময় ব্যবহারকারীর অভিজ্ঞতা উন্নত করতে ট্রান্সপোর্ট স্টোর করা উপযোগী। ট্রান্সপোর্ট উপলভ্য থাকলে, ব্রাউজার সেই অনুযায়ী কাজ করতে পারে এবং এমন UI দেখাতে পারে যা ক্লায়েন্টের সাথে যোগাযোগ করার জন্য পাসকী প্রদানকারীর ব্যবহার করা ট্রান্সপোর্টের সাথে মেলে—বিশেষ করে আবার যাচাইকরণের ক্ষেত্রে যেখানেallowCredentialsখালি থাকে না।
ব্যবহারকারীর অভিজ্ঞতা উন্নত করার জন্য অন্যান্য তথ্য স্টোর করা সহায়ক হতে পারে, যার মধ্যে পাসকী প্রদানকারী, ক্রেডেনশিয়াল তৈরির সময় এবং শেষবার ব্যবহারের সময় অন্তর্ভুক্ত। পাসকী ইউজার ইন্টারফেস ডিজাইন থেকে আরও জানুন।
কোডের উদাহরণ: ক্রেডেনশিয়াল স্টোর করা
আমাদের উদাহরণে আমরা SimpleWebAuthn লাইব্রেরি ব্যবহার করছি।
এখানে, আমরা রেজিস্ট্রেশন রেসপন্স যাচাইকরণকে এর verifyRegistrationResponse ফাংশনে হ্যান্ডওভার করি।
import { isoBase64URL } from '@simplewebauthn/server/helpers';
router.post('/registerResponse', csrfCheck, sessionCheck, async (req, res) => {
const expectedChallenge = req.session.challenge;
const expectedOrigin = getOrigin(req.get('User-Agent'));
const expectedRPID = process.env.HOSTNAME;
const response = req.body;
// This sample code is for registering a passkey for an existing,
// signed-in user
// Ensure you nest verification function calls in try/catch blocks.
// If something fails, throw an error with a descriptive error message.
// Return that message with an appropriate error code to the client.
try {
// Verify the credential
const { verified, registrationInfo } = await verifyRegistrationResponse({
response,
expectedChallenge,
expectedOrigin,
expectedRPID,
requireUserVerification: false,
});
if (!verified) {
throw new Error('Verification failed.');
}
const {
aaguid,
credential,
credentialBackedUp
} = registrationInfo;
// Name the credential based on AAGUID
const name =
aaguid === undefined ||
aaguid === '00000000-0000-0000-0000-000000000000' ?
req.useragent?.platform : aaguids[aaguid]?.name;
const base64PublicKey = isoBase64URL.fromBuffer(credential.publicKey);
// Existing, signed-in user
const { user } = res.locals;
// Save the credential
await Credentials.update({
id: credential.id,
passkey_user_id: user.passkey_user_id,
publicKey: base64PublicKey,
name,
aaguid,
transports: credential.transports || response.response.transports,
backed_up: credentialBackedUp,
registered_at: new Date().getTime()
});
// Kill the challenge for this session
delete req.session.challenge;
return res.json(user);
} catch (e) {
delete req.session.challenge;
console.error(e);
return res.status(400).send({ error: e.message });
}
});
পরিশিষ্ট: AuthenticatorAttestationResponse
AuthenticatorAttestationResponse-এ দুটি গুরুত্বপূর্ণ অবজেক্ট আছে:
response.clientDataJSONহল ক্লায়েন্ট ডেটা-এর JSON ভার্সন, যা ওয়েবে ব্রাউজারের মাধ্যমে দেখা ডেটা। এতে RP-এর উৎস, চ্যালেঞ্জ এবং ক্লায়েন্ট Android অ্যাপ হলেandroidPackageNameথাকে। RP হিসেবে,clientDataJSONপড়লে আপনিcreateঅনুরোধের সময় ব্রাউজার যে তথ্য দেখেছে তা অ্যাক্সেস করতে পারবেন।response.attestationObjectদুটি তথ্য থাকে:attestationStatementযা অ্যাটেস্টেশন ব্যবহার না করলে প্রাসঙ্গিক নয়।authenticatorDataহল পাসকী প্রদানকারীর দেখা ডেটা। RP হিসেবে,authenticatorDataপড়লে আপনি পাসকী প্রদানকারীর দেখা ডেটা অ্যাক্সেস করতে পারবেন এবংcreateঅনুরোধের সময় তা ফেরত দেওয়া হয়।
authenticatorData-এ সর্বজনীন কী ক্রেডেনশিয়াল সম্পর্কে প্রয়োজনীয় তথ্য থাকে যা নতুন তৈরি করা পাসকী-এর সাথে যুক্ত:
- সর্বজনীন কী ক্রেডেনশিয়াল এবং এটির জন্য একটি অনন্য ক্রেডেনশিয়াল আইডি।
- ক্রেডেনশিয়ালের সাথে যুক্ত RP আইডি।
- পাসকী তৈরি করার সময় ব্যবহারকারীর স্ট্যাটাস বর্ণনা করে এমন ফ্ল্যাগ: ব্যবহারকারী আসলে উপস্থিত ছিলেন কিনা এবং ব্যবহারকারীকে সফলভাবে যাচাই করা হয়েছে কিনা (userVerification deep dive দেখুন)।
- AAGUID হল Google Password Manager-এর মতো পাসকী প্রদানকারীর জন্য একটি শনাক্তকারী। AAGUID-এর উপর ভিত্তি করে, আপনি পাসকী প্রদানকারীকে শনাক্ত করতে এবং পাসকী ম্যানেজমেন্ট পৃষ্ঠায় নাম দেখাতে পারবেন। (AAGUID-এর মাধ্যমে পাসকী প্রদানকারী নির্ধারণ করুন দেখুন)
authenticatorData, attestationObject-এর মধ্যে নেস্ট করা থাকলেও, এতে থাকা তথ্য আপনার পাসকী প্রয়োগের জন্য প্রয়োজন, আপনি অ্যাটেস্টেশন ব্যবহার করুন বা না করুন। authenticatorDataএনকোড করা আছে এবং এতে এমন ফিল্ড আছে যা বাইনারি ফর্ম্যাটে এনকোড করা আছে। আপনার সার্ভার-সাইড লাইব্রেরি সাধারণত পার্সিং ও ডিকোডিং ম্যানেজ করবে। আপনি সার্ভার-সাইড লাইব্রেরি ব্যবহার না করলে, সার্ভার-সাইডে কিছু পার্সিং ও ডিকোডিংয়ের কাজ থেকে নিজেকে বাঁচাতে getAuthenticatorData() ক্লায়েন্ট-সাইড ব্যবহার করার কথা বিবেচনা করুন।
পরিশিষ্ট: রেজিস্ট্রেশন সংক্রান্ত উত্তরের যাচাইকরণ
ব্যাকগ্রাউন্ডে, রেজিস্ট্রেশনের উত্তর যাচাই করার মধ্যে নিম্নলিখিত চেকগুলি অন্তর্ভুক্ত থাকে:
- RP আইডি আপনার সাইটের সাথে মিলছে কিনা তা নিশ্চিত করুন।
- অনুরোধের উৎস আপনার সাইটের জন্য প্রত্যাশিত উৎস (প্রধান সাইটের URL, Android অ্যাপ) কিনা তা নিশ্চিত করুন।
- আপনার যদি ব্যবহারকারী যাচাইকরণের প্রয়োজন হয়, তাহলে নিশ্চিত করুন যে ব্যবহারকারী যাচাইকরণ ফ্ল্যাগ
authenticatorData.uvহলtrue। - ব্যবহারকারীর উপস্থিতি ফ্ল্যাগ
authenticatorData.upসাধারণতtrueহওয়ার কথা, তবে ক্রেডেনশিয়াল শর্তসাপেক্ষে তৈরি করা হলে, এটিfalseহওয়ার কথা। - ক্লায়েন্ট আপনার দেওয়া চ্যালেঞ্জের উত্তর দিতে পেরেছে কিনা তা চেক করুন। আপনি অ্যাটেস্টেশন ব্যবহার না করলে, এই চেকটি গুরুত্বপূর্ণ নয়। তবে, এই চেক প্রয়োগ করা একটি পেশাদার পদ্ধতি: এটি নিশ্চিত করে যে আপনি ভবিষ্যতে অ্যাটেস্টেশন ব্যবহার করার সিদ্ধান্ত নিলে আপনার কোড প্রস্তুত আছে।
- নিশ্চিত করুন যে ক্রেডেনশিয়াল আইডি এখনও কোনও ব্যবহারকারীর জন্য রেজিস্টার করা হয়নি।
- ক্রেডেনশিয়াল তৈরি করার জন্য পাসকী প্রদানকারীর ব্যবহার করা অ্যালগরিদমটি আপনার তালিকাভুক্ত অ্যালগরিদম কিনা তা যাচাই করুন (
publicKeyCredentialCreationOptions.pubKeyCredParams-এর প্রতিটিalgফিল্ডে, যা সাধারণত আপনার সার্ভার-সাইড লাইব্রেরির মধ্যে সংজ্ঞায়িত করা হয় এবং আপনার কাছে দৃশ্যমান নয়)। এটি নিশ্চিত করে যে ব্যবহারকারীরা শুধুমাত্র আপনার বেছে নেওয়া অ্যালগরিদমের মাধ্যমে রেজিস্টার করতে পারবেন।
আরও জানতে, SimpleWebAuthn-এর verifyRegistrationResponse-এর জন্য সোর্স কোড চেক করুন অথবা স্পেসিফিকেশন-এ যাচাইকরণের সম্পূর্ণ তালিকা দেখুন।