تغییرات¶
منتشرنشده¶
- فروشگاه نمونه فارسی حرف میزند - منو، سفارشها، فیلدها و وضعیتهایشان، و
دامنههایش - تا عکسهای فارسی مستندات سرتاسر فارسی باشند.
nox -s messagescatalogue آن را هم نگه میدارد.
0.2.1 - آنچه عکسها نشان دادند¶
آنچه عکسهای پنل ادمین، برای مستندات، نشان دادند. چیزی که پروژهای نوشته تغییر نمیکند.
- صفحههای دسترسی متن خودشان را به فارسی میگویند - سرستونهای جدول، مجوزهای خود کتابخانه («میتواند دسترسی بسازد») و اسم اپها انگلیسی بودند.
- breadcrumbهای صفحههای دسترسی همان نوار Djangoاند، روی Django 6.1 هم، که فقط نشانهگذاری تازهاش را رنگ میکند.
- سازندهی قانون عملگرها را با کلمه نشان میدهد - «یکی است از»، نه
is_one_of- به زبان خواننده. - جدول یک بسته در صفحهی ۱۲۸۰ پیکسلی جا میشود. مجوزهای دیگر یک مدل - تأیید، چاپ، مجوزهای یک فیلد - در ردیف جدای خودشان زیر چهار مجوز اصلی میآیند، جایی که پیشتر از کنار صفحه بیرون میزدند.
- کسی که بستهای را از راه نقشش دارد، در همهی صفحههای دسترسی هست. صفحهی افراد و عدد نمای کلی او را جا میانداختند، فهرست بستهها برای بستهای که یک نقش به افراد میدهد هیچ کس را نمیشمرد، صفحهی خود آن «هیچ کس آن را ندارد» نشان میداد، و حذف آن طوری نشان داده میشد که انگار از هیچ کس چیزی نمیگیرد. حالا فهرست میشوند، با علامت از نقششان.
- فیلدی که در کد محافظت شده، به فارسی میگوید کجا از محافظت خارج میشود - «فقط در کد» - جایی که طوری خوانده میشد که انگار آنجا از محافظت خارج شده.
- صفحهی مجوزها با کلمهی فارسی خود کتابخانه نام برده میشود - منو کلمهی Django را برای آن میگفت، و بقیهی صفحهها کلمهی کتابخانه را.
0.2.0 - بازبینی امنیتی¶
یافتههای بازبینی امنیتی 0.1.0. کارهایی را که 0.1.0 میکرد طوری عوض میکند که یک پروژه ممکن است متوجه شود - هر کدام با تغییر علامت خورده - پس به عنوان 0.2.0 منتشر میشود، نه یک وصله. هنوز alpha است: API ممکن است پیش از 1.0 عوض شود.
- صفحهی کاربر در سایت ادمین باز میشود. افزودن یا تغییر کاربر با
UserAdminجنگو برای همه خطای سرور بود. - حساب یک superuser فقط مال superuser است که در سایت ادمین تغییرش دهد یا حذفش کند - رمزش هم. پیشتر هر کسی که میتوانست کاربران را تغییر دهد رمز یک superuser را میگذاشت و با حساب او وارد میشد.
- فیلدی که نقشها از آن خوانده میشوند را فقط superuser مینویسد در سایت
ادمین، پس با
AttributeResolverهیچکس به خودش نقش نمیدهد. resolver خود پروژه فیلدهایش را باRoleResolver.fields()نام میبرد. -
آخرین کسی که میتواند دسترسیها را مدیریت کند در صفحهی کاربر غیرفعال یا حذف نمیشود.
-
دامنه برای چیزی که نوشته میشود هم برقرار است. ردیفی که بیرون از دامنهی
createساخته شود، یا با ویرایش از ردیفهایی که شخص به آنها میرسد بیرون برود، رد میشود و نوشتن برگردانده میشود - در ویوهای Django، در DRF و در سایت ادمین.clearance.writes.require_within_scopeهمین را در ویویی که دستی ذخیره میکند میپرسد. تغییر: اعطایcreateبدون دامنه حالا بهdefault_scopeمدل میرسد، مثل هر اعطای دیگر - یعنی رویScopedQuerySetای که آن را نام نبرده، به هیچ ردیفی. بهcreateدامنه بدهید. - inline و فهرست قابلویرایش فقط ردیفهایی را تغییر میدهند که شخص اجازهی ویرایششان را دارد، و inline فقط آنهایی را حذف میکند که اجازهی حذفشان را دارد. پیشتر هر ردیفی که میدید آنجا قابل تغییر بود.
-
اکشن ادمینی که
permissions=جنگو را نام میبرد روی ردیفهایی اجرا میشود که آن مجوزها به آنها میرسند، نه هر ردیفی که شخص میبیند. -
قانونهای ایمنی از چهار راه دیگر هم برقرارند. هر کدام برای کسی که دسترسی را مدیریت میکرد و هیچچیز از آنچه عوض میکرد نداشت باز بود:
- تغییر ردیفهای یک دامنهی قانونی، هر مجوزی را که در آن داده شده روی همهی ردیفها لازم دارد؛
- پس دادن مجوزی که گرفته شده، داشتن آن را لازم دارد - با دامنههایی که بستههای آن شخص میدهند؛
- اینکه یک اکشن وضعیت از مقدارهای بیشتری بنویسد کار superuser و فایل
ACCESSاست - تغییر: پیشتر کسی که آن را نداشت میتوانست؛ - دادن نقش دومی که سقف را بازتر کند یا بردارد به کسی که زیر سقف است،
role_ceiling_editمیخواهد. -
بستهای که شخص با نقشش شروع میکند بستهی خود اوست: آن را تغییر نمیدهد.
-
فیلد محافظتشده از راه دیگری هم دانسته نمیشود. بدون مجوز دیدنش باز هم خوانده میشد، یا مقدارش تنگ میشد، از این راهها:
- فیلتری که در نوار نشانی پنل ادمین تایپ شود (
?price__gte=)، و سلسلهمراتب تاریخ - هر دو حالا رد میشوند؛ - serializerی که داخل یک serializer محافظتشده است، چه نوشته شده باشد چه
depthساخته باشدش؛ SearchFilterوOrderingFilterخود DRF که نامش را ببرند، روی ویویی باProtectedSerializerMixin(کهScopedModelViewSetدارد)؛- proxy مدلش، یا مدلی که آن را از والدی با جدول خودش به ارث میبرد - روی همهی آنها همان یک جفت مجوز را دارد.
- یک مقدار با هر نامی که فرستاده شود رد میشود: فیلد serializer با
source='status'میتوانست مقداری را بنویسد که یک اکشن وضعیت ادعا کرده، و یک رابطه میتوانست با نام ستونش (officer_id) نوشته شود. -
فرم پنل ادمین فقط ردیفهای مرتبطی را پیشنهاد میدهد که شخص اجازهی دیدنشان را دارد، و آن یکی را که ردیف از قبل دارد. تغییر: انتخاب ردیف مرتبط در آنجا
viewروی مدل آن را میخواهد. -
visible()از خود queryset میپرسد. ویو، پنل ادمین و policy تابعvisible()را صدا میزدند که هیچوقت ازvisible_toخودScopedQuerySetنمیپرسید - پسSignedInReadQuerySetبه ویو هیچچیز نشان نمیداد، و بازنویسیای که تنگتر میکرد نادیده گرفته میشد. حالا پاسخ خود queryset را میگیرند. - دامنهای که با queryset جواب میدهد ردیفهایی را که دربارهشان پرسیده شده نگه میدارد. وقتی تنها بود جای queryset را میگرفت، و هر فیلتری که ویو گذاشته بود - مثلاً tenant - از بین میرفت.
- E007 هر backendی را که روی
ModelBackendساخته شده رد میکند، نه فقط همان یک نام را: اگر پیش از backend کتابخانه میآمد، همهی سلبها را برمیگرداند. with_permهمان را میگوید کهhas_perm- بدون کسی که مجوز از او گرفته شده یا سقفش جلویش را میگیرد، و با کسی که با نقشش آن را دارد.- صفحهها بهجای خطا جواب میدهند. کلید بستهای که عدد نیست 404 است؛ نامی که از ستونش بلندتر است رد میشود و دلیلش گفته میشود - SQLite آن را کامل نگه میداشت و PostgreSQL خطای سرور میداد.
- قانونی که با
Noneمقایسه میکند موقع ذخیره رد میشود: به شکل''نگه داشته میشد و از آن به بعد به هیچ ردیفی نمیرسید.is_emptyهمین را میگوید. -
کوئری کمتر. صفحهی نمای کلی و صفحهی اکشنها پایگاه داده را به تعداد ثابتی میخوانند (پیشتر حدود ۹۰ بار، و یکی بیشتر برای هر بسته؛ حالا ۱۹ بار)، و ذخیرهی یک بسته دیگر برای هر مجوز یک بار آن را نمیخواند.
-
رد شدن به زبان خواننده گفته میشود. آنچه قانونهای ایمنی رد میکنند، و ایراد یک قانون، یک اکشن وضعیت، یک فیلد محافظتشده یا یک نام، هر زبانی که صفحه داشت به انگلیسی گفته میشد. هر کدام برای ترجمه علامت خورده و به فارسی گفته میشود؛
AccessRefused.ruleهمچنان قانون را برای کد نام میبرد. -
serializer محافظتشده فقط ردیفهای مرتبطی را میپذیرد که شخص اجازهی دیدنشان را دارد، مثل فرم پنل ادمین. تغییر: APIای که ردیف مرتبط انتخاب میکند
viewروی مدل آن را میخواهد؛ دادهی مرجعی که همه از آن انتخاب میکنند باSignedInReadQuerySetخوانده میشود، مثل شعبههای پروژهی نمونه. - مجوزی که مدل دیگری دارد دوباره ساخته نمیشود. مجوز یک فیلد، یا یک اکشن وضعیت، با codename مجوز مدل دیگری در همان app همان یکی میشد: در پنل ادمین رد میشود، و موقع راهاندازی برای فیلدی که در کد محافظت شده (E012).
- دو تغییری که هر کدام میتوانند هیچکس را برای مدیریت دسترسی باقی نگذارند نوبت میگیرند: بررسی، ردیف آن مجوز را قفل میکند، هر جا پایگاه داده بتواند.
- مهاجرت 0006 بدون از دست رفتن چیزی برمیگردد: ردیفها به ستونها برمیگردند. در
جهت جلو، شرطی که با
Noneمقایسه میکردis_emptyمیشود. - موارد کوچکتر. بله یا نهای که مثل فرم فرستاده شود (
on،true) همان خوانده میشود، جایی که یک اکشن وضعیت ادعایش کرده. قانون روی رابطهی generic بهجای خطا رد میشود. اکشن وضعیتی در فایلACCESSکهtoیاfromآن فهرست نیست یک ایراد گفتهشده است، نه traceback. syncای که روی پایگاه دادهی تست رد میشود این را میگوید.
و آنچه اصلاحهای این بازبینی جا انداخته بودند:
- ردیفهایی که با هم فرستاده میشوند هم در دامنه میمانند. فهرستی که یکجا ساخته
میشد (
many=True) ردیف به ردیف و بدون بررسیای که یک ردیف تنها داشت ذخیره میشد؛ حالا تکتک ردیفها بررسی میشوند، و فهرست یا کامل ذخیره میشود یا اصلاً. visible_toخود یک queryset میتواندvisible(self, ...)را صدا بزند، همانطور که 0.1.0 میکرد: درون آن،visibleاز روی اعطاها جواب میدهد. پیشتر دوباره همان بازنویسی را صدا میزد، بیپایان.- API ردیف مرتبطی را که یک ردیف از قبل دارد نگه میدارد، حتی اگر شخص اجازهی دیدنش را نداشته باشد - ویرایش پرداختی که شخص وامش را نمیبیند رد میشد. این بررسی source یک فیلد را پیش از آنکه DRF تنظیمش کند میخواند.
- هزینهی
with_permهر چند نفر که مجوز را داشته باشند یکی است: سقف از همه با هم پرسیده میشود، نه از تکتکشان. - هر خط کتابخانه را یک تست اجرا میکند، و اگر کمتر باشد تستها fail میشوند
(
fail_under = 100).
و آنچه این بازبینی باز گذاشته بود:
- یک حساب را فقط کسی تغییر میدهد یا حذف میکند که دستکم همهی آنچه آن حساب دارد را
داشته باشد. کسی که میتوانست کاربران را تغییر دهد رمز یکی از مدیران دسترسی را
میگذاشت و با حساب او وارد میشد؛ فقط حساب superuser محافظت شده بود. این در
policy.allowsپرسیده میشود، پس همهی درها آن را میپرسند. تغییر: پشتیبانی که رمزها را عوض میکند باید آنچه حسابهایش دارند را داشته باشد. - حذف چیزی را که شخص اجازهی حذفش را ندارد با خود نمیبرد. حذف یک وام از طریق API
پرداختهایش را هم حذف میکرد، برای کسی که اجازهی حذف هیچ پرداختی را نداشت. حذف
آبشاری به مدلی که کتابخانه از آن محافظت میکند در
perform_destroyخود DRF،DeleteViewخود Django و پنل ادمین پرسیده میشود؛clearance.writes.require_deletableهمین را دستی میپرسد. - قانونی که به مدل دیگری میرسد نویسندهای میخواهد که همهی آن مدل را ببیند. شرطی
روی
applicant__emailافراد را برای کسی میخواند که اجازهی دیدن هیچکدام را نداشت. - کلاس مجوز فیلد تغییرنامداده را با فیلدی که مینویسد میخواند. viewای که
serializer محافظتنشده را موقع اجرا انتخاب میکرد - بیرون از دید E003 - میگذاشت
decisionباsource='status'وضعیت را بنویسد. DjangoFilterBackendاز django-filter فقط با فیلدهای خواندنی فیلتر میکند، روی viewای باProtectedSerializerMixin، همانطور که فیلترهای خود DRF میکنند.-
راهنما میگوید یک پردازهی طولانی با آنچه روی کاربر نگه داشته شده چه کند: کاربر را دوباره بخواند، یا
forget_grants(user). -
در بررسی اصلاحهای بالا پیدا شد، و حالا برقرار است:
- فهرست قابلویرایش حسابها حسابی را که بیش از شخص دارد دست نمیزند - روی Django 5.2 ایمیل یک مدیر را عوض میکرد، که راهی به حساب اوست؛
- هیچ کس روی حساب خودش فیلدی را نمینویسد که یک دامنهی قانونی آن را بهعنوان مالِ
شخص میخواند (
region، برای «منطقهی شخص») - در پنل ادمین، فرم محافظتشده یا API: این همان ردیفهایی است که به آنها میرسد؛ - تغییر: حسابی که همان دامنه را فقط به نام دارد، وقتی بالاتر حساب نمیشود که
آن دامنه برای هر کسی به همان ردیفها برسد. دو نفر که «شعبهی خودش» را دارند هر
کدام شعبهی خودشان را دارند؛ تغییر حساب دیگری آن مجوز را در
allمیخواهد؛ - تغییر: حذف، از هر مدلی که حذف آبشاری به آن میرسد و مجوز
deleteدارد میپرسد، نه فقط مدلهایی که دامنه یا مجوز تعریفشده دارند. حذف یک وام،deleteروی صورتحسابهایش را هم میخواهد.
و آنچه بررسی اینها پیدا کرد:
- inline و فهرست قابلویرایش hook خود policy را برای هر ردیف میپرسند - مثلاً «سفارش تحویلشده ویرایش نمیشود». پیشتر فقط دامنه را میپرسیدند، پس hookی که یک ردیف را رد میکرد دور زده میشد: در inline روی همهی نسخههای Django، و در فهرست قابلویرایش پیش از 6.1.
PERSON_FIELDSفیلدهایی از کاربر را نام میبرد که یک دامنهی کد میخواند -('branch',)برایQ(branch=user.branch_id)- و این فیلدها روی حساب خود شخص قفل میشوند، همانطور که فیلدهایی که یک دامنهی قانونی میخواند. کتابخانه نمیتواند دامنهای را که در کد نوشته شده بخواند.CASCADE_UNASKED_APPSاپهایی را نام میبرد که حذف، ردیفهایشان را بدون پرسش با خود میبرد - اپی که برای هر حساب یک توکن یا نشانی نگه میدارد، وdeleteآن را به کسی نمیدهند. مدلی که کتابخانه از آن محافظت میکند در هر حال پرسیده میشود.
0.1.0 - نخستین انتشار¶
Alpha: همهی بخشها ساخته و تست شدهاند، ولی هنوز در پروژهای با مدلهای واقعی به کار نرفتهاند، پس API ممکن است پیش از 1.0 عوض شود.
- بستهها - همان گروههای Django، که هر مجوز در آنها با یک دامنهی ردیف داده میشود؛ گرفتن یک مجوز از یک شخص، با دلیلش.
- دامنههای ردیف - در کد روی یک
ScopedQuerySet، یا ساختهشده از قانونها در پنل ادمین؛visible_to(user, action)آنها را با تعداد ثابتی کوئری میخواند. - فیلدهای محافظتشده - با یک مجوز خوانده و با مجوزی دیگر نوشته میشوند، در کد یا در پنل ادمین، و از هر serializer، فرم، قالب، صفحهی ادمین و قانونی کنار گذاشته میشوند.
- اکشنها - اکشنهای وضعیت که فقط خودشان مقدارهایشان را مینویسند؛ اکشنهایی که
در viewها، viewsetها و اکشنهای ادمین پیدا میشوند، با مجوزهایی که
migrateمیسازد. - Policyها -
BasePolicyبرای قانونهایی که هیچ مجوزی نمیتواند بگوید، وModelPolicyبرای هر مدل دیگر. - viewهای Django و DRF -
PolicyRequiredMixin،ScopedQuerySetMixin،ProtectedFieldsViewMixin،policy_required؛ModelPolicyPermission،PolicyPermission،ScopedModelViewSet، و رد کردن نوشتن، فیلد به فیلد. - پنل ادمین - هر
ModelAdminاز policyها میپرسد، و صفحههای دسترسی: نمای کلی، بستهها به شکل جدول، افراد، مجوزها، سازندهی قانون، فیلدهای محافظتشده، اکشنها؛ به فارسی راست به چپ. - قانونهای ایمنی - هیچ کس به خودش بیشتر نمیدهد، چیزی را که ندارد نمیدهد، و کاری نمیکند که هیچ کس نتواند دسترسی را مدیریت کند.
- دسترسی به صورت کد - فایل
ACCESSوclearance_sync، با--dry-run،--checkوSYNC_ON_MIGRATE. clearance.roles- نقشها با بستههای آغازین و یک سقف.clearance.translations- اسم مجوزها، بستهها و نقشها در همهی زبانها.- بررسی - system checkها موقع بالا آمدن پروژه، و
clearance_checkبرای چیزهایی که فقط پایگاه داده میتواند بگوید. - انگلیسی و فارسی در همه جا؛ Python 3.11 تا 3.14، Django 5.2، 6.0 و 6.1، DRF 3.16 و بالاتر.