Node Master – Telegram
Node Master
1.03K subscribers
24 photos
2 files
156 links
Group Chat: @nodemastergp
Admin: @napoleon_n1
Download Telegram
Node Master
class BuggyCls { #age; set age(value) { this.#age = value; } get age() { return this.#age; } sum2() { return this.#age + 2; } } این تیکه کد ساده یک باگ ترسناک داره که ممکنه به راحتی به چشم نیاد. اینجور باگ ها روی پروداکشن یکم سخته…
بزارید قبل از توضیح باگ اول راجع به #age توضیح بدم.
وقتی شما در یک کلاس قبل از هر attribute اگر # بزارید اون تبدیل به private میشه. این نوع private کردن با استفاده از کلمه private در typenoscript متفاوت هست.
شما وقتی با # یک فیلد رو private کنید در حقیقت خود انجین تضمین میکنه private بودن رو ولی در typenoscript صرفا فقط یک syntax در زمان compile و قبل از transpile میباشد. بزارید با مثال توضیح بدم.
class Simple {
private age = 24;
}

const obj = new Simple();

console.log("age" in obj);

خط سوم با استفاده از in ما چک میکنیم که آیا obj یک attr با نام age دارد یا خیر. اگر زبانی مثل جاوا بود قطعا جواب false بود ولی اینجا true برمیگردونه. شما حتی میتونید type cast کنید و مستقیم دسترسی به age داشته باشید!
ولی اگر خط بالا رو با #age بنویسید جواب false میگیرید که منطقی هست چون خود js engine این تضمین رو بهمون میده که private هست ( حالا که چطور این تضمین رو بهمون میده خودش یک بحث طولانی دیگ هست که اینجا مورد نظر ما نیست)

حالا سوال پیش میاد از کدوم استفاده کنیم برای private کردن فیلد ها؟
جواب خیلی بستگی داره و باتوجه به تحقیقی که من کردم خیلی دو دستگی و سلیقه ای هست این بخش. البته در آینده قطعا آدما بیشتری سمت این ویژگی خواند رفت و چون این داخل ES2022 اضافه شده و خیلی جدیده کلا طول میکیشه تا همه استفاده کنن چون که ویژگی جدیده هست و داخل آموزش ها معمولا نمیگن.

نکته بعدی این که وقتی داشتم سوال بالا رو طراحی میکردم قصد داشتم یک باگ خیلی معروف رو برسی کنیم ولی بیشتر که رو سوال دقت کردم رسیدم به جمله معروف "javanoscript is garbage" چون اون سوال حتی من که طراحیش کردم یک باگی داشت که خودم دوباره بهش دقت نکرده بودم. البته برمیگرده به ساختار و فلسفه زبان که بنظرم فرصت خیلی خوبی هست عمیق تر بشیم
#Tip
👍5
NodeMaster.ir
Coming Soon!
👍11
همکاری در پوزیشن توسعه دهنده بک اند
ما یک‌شرکت فناور مستقر در پارک علم و فناوری دانشگاه تهران و بازوی فناوری هلدینگ معدنی سنگ آهن هستیم. ما به دنبال یک همکار توسعه دهنده در پوزیشن بک اند با استک nest هستیم و توانایی های مورد انتطارمون:
تسلط بر typenoscript و فریمورک nest
توانایی کار با git
توانایی تست نویسی
توانایی داکیومنتیشن
توانایی کار گروهی و حل مساله
حقوق و دستمزد را به صورت توافقی و بر  اساس نوع همکاری تعیین میکنیم.
ضمنا محصول یک وب اپلیکیشن تخصصی در زمینه هوشمندسازی معادن است.
Naghshtech@gmail.com
@Ali_ramez

#Work
👍2
رشته پست مربوطه :‌ https://news.1rj.ru/str/NodeMaster/81

خب بریم سراغ باگی که قرار بود راجع بهش صحبت کنیم. بزارید یکم راجع تاریخچه باحال این باگ صحبت کنیم.
Null References: The Billion Dollar Mistake
اولین بار این null رو در زبان ALGOL در سال 1965 درست کرد فقط به دلیل این که پیاده سازیش خیلی راحت بود براش. کلا درمورد null ها همیشه همه جا بحث زیاده و به این دلیل بهش میگن billion doller mistake که یهویی داخل runtime یچیزی میبینی که نباید و برنامه کرش میکنه. مقالات زیادی راجع بهش هست که میتونید مطالعه عمیق تری داشته باشید راجع بهش و یک تایم دیگه خود این موضوع رو عمیق تر صحبت میکنیم.
توضیح باگ‌: شما اگر قبل از set کردن مقدار age با استفاده از setter متد sum2 رو invoke کنید به دلیل این که مقدار #age تعریف نشده و undefined (یا همون null‌) هست و وقتی یک عدد رو با undefined جمع کنید مقدار NaN رو میگیرید که همین خودش یک موضوع دیگس.
بزارید اول این رو بگم که یکی از دلایلی که میگن "js is garbage" همین Billion Dollar Mistake به دلیل این که نه تنها یک مقدار بلکه دو مقدار برای نشان دادن null داریم یعنی خود null و undefined و هرچی راجع به جک این موضوع صحبت کنیم واقعا کمه!
این باگ رو شما اگر از #typenoscript استفاده کنید در زمان compile میتونید جلوگیری کنید به دلیل این که ts اگر strictnullcheck در ts فعال باشه شما رو مجبور میکنه که این رو درنظر بگیرید.
class BuggyCls {
#age?: number;
set age(value) {
this.#age = value;
}

get age() {
return this.#age;
}

sum2() {
if (this.#age === undefined || this.#age === null) {
return this.#age + 2;
}
throw new TypeError("Please set a number value for age");
}
}

شما در خط دوم به ts میگید که این مقدار میتواند undifiend هم باشد و در متد sum شما رو مجبور میکنه که از guard استفاده کنید تا کدتون رو امن کنید. به این موضوع میگن null safety. یک روش دیگ هم برای تعریف فیلدی که میتواند null هم باشد هست که من معمولا از اون روش استفاده میکنم.
#age: number | null = null;

هر دو روش تفاوتی در نهایت ندارن و سلیقه هست من به این دلیل از این استفاده میکنم چون خیلی explicit تر هست و معمولا میگن از undifiend مستقیم استفاده نکنید و برای جاهایی بزاریدش که خود js engine اون رو برمیگردونه.
این موضوع هم البته صرفا یک practise هست و شما باید در نهایت استایل خودتون رو داشته باشید.

مطلب بعدی راجع به NaN خیلی صحبت میکنیم این همون موضعی بود که حتی من هم وقتی داشتم سوال طرح میکردم حواسم بهش نبود. مطلب بعدی جالبه چون که به زبان های دیگ مثل پایتون نگاهی میندازیم تا درک بهتری از دلیل این موضوع داشته باشیم.

#Tip
👍9
Node Master
رشته پست مربوطه :‌ https://news.1rj.ru/str/NodeMaster/81 خب بریم سراغ باگی که قرار بود راجع بهش صحبت کنیم. بزارید یکم راجع تاریخچه باحال این باگ صحبت کنیم. Null References: The Billion Dollar Mistake اولین بار این null رو در زبان ALGOL در سال 1965 درست کرد فقط به دلیل…
در پست قبلی راجع به اصل باگ توضیحاتی دادیم ولی رسیدم سروقت این که چرا ما NaN میگیریم. بزارید با یک مثال در #python و #javanoscript رو کنار هم بزاریم و اونجا میتونیم بهتر متوجه بشیم.
>>> 2 + "text"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

> 2 + "text"
'2text'

این دو خط خیلی شبیه به هم هستند هردو یک مقدار string رو با یک مقدار integer جمع کردیم ولی جواب نهایی خیلی متفاوت هست. دقیقا همین رفتار باعث میشه که زبان ها رو به دو دسته تقسیم کنیم
- weakly typed
- strong type
قبل از این که توضیح بدم راجع به این دو این رو در نظر بگیرد که #python یک زبان strong type و #javanoscript یک زبان weak type هست و حالا با دونستن این فکت میتونیم توضیحات رو کامل تر کنیم.
به عنوان مثل در زبان های strong type اگر دو expresion از type های مختلف بخواد پردازشی روشون انجام بشه خود compiler یا interpreter جلوگیری میکنه از این کار مثل کد پایتون بالا که به صراحت میگه هردو باید یک type باشند و فرایند این تبدیل باید به صورت explicit توسط برنامه نویس انجام شود ولی در زبان های weakly type نتیجه میشه تکه کد js که این به نوعی خیلی میتونه ترسناک باشه! حالا اگر بخوایم نتیجه شبیه به کد js داشته باشیم منظور از explicit بودن در مثال پایین میبینید.
>>> str(2) + "text"
'2text

اینجا میبینید که برنامه نویس از فانکشن str برای تبدیل integer به string به صراحت ( explicitly ) استفاده کرده و منظور از explicit بودن این هست.
تفاوت زبان های strong و weak type به همینجا خطم نمیشه و ساعت ها میشه راجع بهش صحبت کرد ولی خب در همین حد فعلا کافی هست چون موضوعات دیگه ای هم هست که باید اشاره کنیم.

بزارید من اینجا یکبار دیگ تاکید کنم که "زبان های Weakly type میتوانند خیلی ترسناک باشند." بزارید این رو یکم بازتر کنم براتون با مثال
> null + 2
2
> undefined + 2
NaN

>>> None + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'

داخل سوالی که بالا طرح کرده بودم دقیقا امکان داشت این اتفاق تک کد بالا پیش بیاد که مقدار undefined با 2 جمع بشه و اینجا javanoscript هیچ اروری به شما نمیده و برنامه روند عادی خودش رو طی میکنه و خدا فقط میدونه کی و کجا یک validation از این جلوگیری کنه. حتی امکان داره ماه ها این باگ ها داخل کدتون بمونه و شما خبر نداشته باشید و از اون بدتر امکان ایجاد record های خراب داخل database هم هست. نکته جالب اینجا بود که وقتی integer رو با null جمع کردم و عدد 2 رو گرفتم خودم سوپرایز شدم. کلا weakly type ها همیشه میتونن شما رو سوپرایز کنن.
ولی خب به عنوان مثال در زبان strong type به صراحت interperter گیر میده و حتی ممکنه برنامه crash کنه.

این نکته خیلی مهم رو توجه کنید که این به معنی بد بودن weakly type lang ها یا خوب بودن strong type lang ها نیست هرکدوم مزایا و معایب خودشون رو دارن و این ما هستیم که باید از اینها درست استفاده کنیم. فقط باید این رو درنظر بگیرید که در زبان ها weakly type باید خیلی خیلی دقت بیشتری کنیم.

نظر شخصی :‌
- در اینجور مواقع من ترجیح میدم برنامه crash کنه تا در سکوت به کار خودش ادامه بده چون crash کردن خیلی خسارت کمتری وارد میکنه تا دیتای خراب روی دیتابیس

سخن پایانی این که این بحث خیلی بزرگتر هست و من سعی کردم به صورت کوتاه اشاره کنیم. یکم طولانی شد این پست هم و این که امیدوارم براتون مفید باشه.

فکر میکردین پشت پرده یک NaN گرفتن اینقدر داستان باشه؟ کامنت کنید😂
#Tip
👍8
Node Master pinned «NodeMaster.ir Coming Soon!»
مرسی از همه شما واقعا باورم نمیشه ۳۰۰ نفر شدیم❤️🎉
امیدوارم مطالب مفید باشه براتون واقعا انگیزم بیشتر شد
👍29
Node Master
معمولا وقتی در حال پیاده سازی Password Auth در Backend برا خودمون هستیم برای امنیت که در صورت leak شدن database پسورد ها رو به صورت Hash ذخیره میکنیم. ۳ الگوریتم پر استفاده برای hash کردن پسورد ها وجود داره به نام های Bcrypt , Scrypt و Argon2 که مرسوم ترین…
اگر در NodeJS برای وب سرورتون Auth service مینویسید و اگر فرایند Auth شما بر پایه password باشد. معمولا به این صورت مقایسه پسورد صورت میگیرید.
if (hashed_pass_from_db === hashed_pass_from_input) {
console.log("sucess")
}

این تکه کد یک مشکل امنیتی خطرناک داره که به چشم نمیاد به راحتی. این مشکل هم دقیقا بخاطر استفاده از "===" هست.
حالا این مشکل چیه و چطور رفعش کنیم. به این باگ امنیتی میگن Timing attack.
اینطور کار میکنه که با استفاده brute force هربار یک پسورد رو سمت back-end ارسال میکنند و با استفاده از زمان response حدس میزنند که چندرصد این پسورد درسته و اینقدر این کار میکنن تا پسورد درست رو بدست بیارن.
اگر از کتابخونه های bcrypt استفاده میکنید معمولا به روش امن براتون پسورد رو چک میکنند اما اگر از scrypt که قبلا توضیح دادم استفاده میکنید شما باید از یک function کمکی در ماژول crypto استفاده کنید.
crypto.timingSafeEqual(Buffer.from("a"), Buffer.from("a"))

این فانکشن زمان مقایسه رو constant میکنه. یعنی زمان مقایسه پسورد اشتباه با درست همیشه یکی هست و اینطوری attacker نمیتونه حدس بزنه. بدون این موضوع شخص attacker یکم تلاش کنه با تفاضل بین پسورد ها به راحتی به پسورد میرسه.

این ویدیو خیلی قشنگ این مشکل امنیتی رو توضیح میده و خودش براتون با مثال یک timing attack هم انجام میده ‌( ویدیو به زبان پایتون هست ولی حتما ببینید )
https://www.youtube.com/watch?v=XThL0LP3RjY
👍18
Node Master
در پست قبلی راجع به اصل باگ توضیحاتی دادیم ولی رسیدم سروقت این که چرا ما NaN میگیریم. بزارید با یک مثال در #python و #javanoscript رو کنار هم بزاریم و اونجا میتونیم بهتر متوجه بشیم. >>> 2 + "text" Traceback (most recent call last): File "<stdin>", line 1,…
یکی از قابلیت های خیلی خوب #typenoscript که خیلی کم استفاده میشه "type predicate" هست. به این شکل هست که شما در runtime میتونید یک interface رو valid کنید. همونطور که میدونید interface ها در typenoscript کلا در کد transpile نمیشوند و معمولا اکثرا با استفاده از type cast میان یک object رو تبدیل میکنن به interface. بزارید مثال بزنم.
interface IUser {
name: string;
age: number;
}

function main() {
// data will come in runtime from result of an api call.
const data: any = { username: 'imanhpr' };
const castedData: IUser = data; // Warning
}

اینجا یک interface داریم که attr هاش مشخصه ولی همینطوری که میبینید castedData قرار هست یک object باشه که اون interface رو داشته باشه ولی خب در حقیقت data از یک جنس دیگس و تایپ اسکریپت اینجور مسایل رو نمیتون پیدا کنه و ما باید
بهش کمک کنیم.
نیاز به یک چیزی داریم که در runtime بتونه صدرصد به من اطمینان بده که type درستی در اون object هست. اینجاس که "type predicate" میاد به نجات ما.

function isUser(input: unknown): input is IUser

معمولا یک فانکشن هست که یک ورودی با تایپ نامشخص رو میگیره و تبدیل میکنه به یک class یا interface یا type و convention هم این هست که با is شروع میشن مثل isProduct , isAdmin و ... .
حالا چطور ما در runtime ثابت کنیم که input ما کاملا interface رو implemet کرده.
function isUser(input: unknown): input is IUser {
return (
typeof input === 'object' &&
'name' in input &&
'age' in input &&
typeof input.age === 'number' &&
typeof input.name === 'string'
);
}

با استفاده از کمک کلمات کلیدی typeof و in در #javanoscript. با استفاده از typeof مشخص میکنیم که تایپ یک object چی هست به عنوان مثال وقتی input تایپش unknown هست یعنی ما هیچی نمیدونیم ازش پس اول میایم میگیم اگر object بود ادامه.
بعد با کمک in چک میکنیم که اون attr ها وجود داشته باشند و بعد دوباره با typeof تایپ اون attr ها رو چک میکنیم که درست باشند.
در حقیقت اینجا به صورت خیلی imperative شکل و ظاهر interface رو دارید replicate میکنید در runtime. در حقیقت دوتاشون یک کار میکنن ولی در جاهای مختلف. یکیشون در runtime و اون یکی در compile time. این نکته در زبان ها دیگ یکم متفاوت هست یعنی
جاوا یا golang یکم متفاوت هست.

حالا اگر همه این ها رو جمع کنیم کد کامل به این شکل میشه
interface IUser {
name: string;
age: number;
}

function isUser(input: unknown): input is IUser {
return (
typeof input === 'object' &&
'name' in input &&
'age' in input &&
typeof input.age === 'number' &&
typeof input.name === 'string'
);
}

function main() {
// data will come in runtime from result of an api call.
const data: any = { username: 'imanhpr' };
if (isUser(data)) {
// logic
}
throw new TypeError('Invalid user');
}


نکته اینجا هست که شما type narrowing هم در if block میگرید و میتونید استفاده کنید و صدرصد به شما safety هم در compile time و هم در runtime میده و مجبورین اون case که اگر این interface هم نبود هندل کنید.

#Tip
👍5
یک بلاگ پست خیلی خوب پیدا کردم از جمع بندی محبوب ترین فریمورک های کل اکوسیستم #NodeJS
بنظرم حتما نگاهی بهش بندازید میتونه در انتخابتون برای بازار کار خیلی تاثیر گذار باشه.
https://stackdiary.com/node-js-frameworks/

#NodeWeekly
👍7
شب یلدا همگی مبارک باشه دوستان❤️🍉
👍25👎1
گاهی اوقات در زمان توسعه برنامه نیاز است که از یک Object یک کپی ایجاد کنیم و Object اصلی رو به هیچ عنوان mutate نکنیم. برای کپی کردن object معمولا دو حالت دارد.
- deep copy
- shallow copy
بزارید با مثال براتون تفاوت این دو مدل رو توضیح بدم.
const user = { name: 'iman', address: { city: 'tehran' } };
اول با shallow copy شروع میکنیم
const user = { name: 'iman', address: { city: 'tehran' } };
const shallowCopyUser = { ...user };
یکی از ساده ترین تکنیک ها استفاده از spread operator برای ایجاد shallow copy هست و اگر شما با react یکم کار کرده باشید این pattern قطعا استفاده کردین. حالا سوال پیش میاد که shallow کپی چی هست ؟
کلا shallow copy به زبان ساده به معنی کپی کردن primitive attr های لایه اول میباشد و refrence type ها فقط کپی نخواهند شد. برای توضیح دقیق این موضوع باید یکم درمورد ساختار memory و pass by value و pass by refrence صحبت کنیم که فعلا اینجا خارج از بحث ما هست. فقط این نکته رو بدونید که #javanoscript یک زبان pass by refrence میباشد.
ما یک مفهومی داریم به اسم object identity که خیلی خلاصه بخوام توضیح بدم به این معنی هست که آیا دو object به یک refrence اشاره دارند یا خیر.
const user = { name: "iman", address: { city: "tehran" } };
const userRef = user;
console.log(user === userRef);
در این مثال با استفاده از "===" ما identity check انجام میدهیم به این صورت که اگر دوطرف به یک reference ( یک خانه در حافظه‌ ) اشاره کنند برابر هستند که اینجا دقیقا هردو دارند به یک ref اشاره میکنند پس جواب true هست.
حالا شما اگر مثال اول رو identity check انجام بدید جواب false هست به این دلیل که شما مقادیر رو کپی کردین در یک خانه حافظه جدید و ref ها متفاوت هستند.
console.log(user === shallowCopyUser);
اینجا لایه اول که کپی شدن ref های متفاوت دارن و جواب false هست که منطقی هست ولی نکته shallow copy دقیقا با مثال پایین معنی پیدا میکنه.
const user = { name: "iman", address: { city: "tehran" } };
const userRef = user;
const shallowCopyUser = { ...user };
console.log(user.address === shallowCopyUser.address);
همونطور که بالا دیدیم اثبات کردیم که shallowCopyUser به یک خانه حافظه جدا اشاره دارد ولی اگر یک nested object داشته باشیم و اون رو با نسخه اصلی مقایسه کنیم جواب true در میاد یعنی به خونه حافظه اصلی اشاره داره و کپی نشده!
و این دقیقا میشه shallow copy. حالا با توجه به این توضیح مفهوم deep copy رو خیلی ساده تر میشه متوجه شد. deep copy به این معنی است که تمام nested ref ها هم کپی و در یک خانه جدید در حافظه ایجاد شوند.
حالا اگر بخوایم deep copy انجام بدیم میتونیم از روش های مختلف دوباره این کار رو انجام بدیم.
const user = { name: "iman", address: { city: "tehran" } };
const deep1 = JSON.parse(JSON.stringify(user)); // classic js
const deep2 = structuredClone(user); // es6
console.log(user.address === deep1.address);
console.log(user.address === deep1.address);
قدیما برای copy کردن از json کمک میگرفتن به این صورت که یک serialize و deserialize انجام میگفرت و نتیجه میشه deep1. نکته این هست که اصلا این روش نه کار قشنگی هست و نه performance خوبی داره. در es6 یک فانکشن خیلی خوب اضافه شد به js به اسم structuredClone که این کار رو خیلی برای ما بهتر و قشنگ تر انجام میده و کلا برای این کار ساخته شده پس شما هم باید از این روش در برنامه های خودتون استفاده کنید.

ممکنه یکم براتون identity check و object identity سخت باشه درکش اگر دوست داشتید مثال پایتونی بزنم که اونجا خیلی دقیق تر و میشه توضیح داد درمورد این ساختار و رفتار.
#tip
👍19
چند روز پیش Deno 1.39 منتشر شد و ویژگی جدیدی که اضافه شده WebGPU هست. کلا تغیرات خیلی زیادی داشته که بنظرم یک نگاهی بندازید خودتون.
حالا چرا اینقدر WebGPU مهم هست؟ اگر تا حالا بازی های تحت وب مثل https://krunker.io/ انجام داده باشید شاید براتون سوال باشه که چطور محیط های که نیاز به GPU دارن رو روی browser render میکنن.
یک API بود به اسم WebGL که خیلی از این مدل بازی ها رو با استفاده از این API میساختن. مدتی هست من خیلی درمورد WebGPU میشنوم که یک API جدیدتر هست و performance بهتری داره.
جزیات این آپدیت رو میتونید از اینجا ببینید.
https://deno.com/blog/v1.39
👍4
Node Master
یکی از موضوعاتی که واقعا جای خالیش در nodejs std حس میشه. پیاده سازی http3 هست. امروز داشتم گشت گذار میزدم و این library رو پیدا کردم. این لایبرری رو بیشتر برسی میکنم. https://github.com/unjs/h3
تیم SocketIO واقعا من رو سوپرایز کردن!
آپدیت 4.7 برای حدود 6 ماه پیش هست و در این آپدیت WebTransport رو اضافه کردن.
برای Full duplex Bidirectional communication پروتکل های مختلف وجود داره که پر استفاده ترینشون برای client to server همین web socket هست که همه میشناسیم.
پروتکل Web Socket روی HTTP/1.1 ( و فکر کنم HTTP/2 ) معمولا سوار میشه که همه میدونیم.
اما پروتکل WebTransport خیلی جدید هست و معمولا adaptation پروتکل ها فرایند خیلی کندی هست. به عنوان مثال پروتکل HTTP/1.1 سال 1999 منتشر شد و هنوز اکثر سایت ها استفاده میکنند. اصن شما وقتی با Express وب سرور درست میکنید روی پروتکلی هست که برای سال 1999 ساخته شده!
اما پروتکل WebTransport از HTTP/3 داره استفاده میکنه و یک Performance gain زیاد به نسبت WebSocket محسوب میشه.
نکته دیگ که خیلی من رو کنجکاو میکنه کلا adaptation rate برای HTTP/2 خیلی کند بود و کلا خیلیا اصلا نیازی ندیدن که مهاجرت کنن. اما adaptation rate پروتکل HTTP/3 خیلی بیشتره. این موضوع من رو کنجکاو میکنه که دلم بخواد یک تایم بزارم دقیق این پروتکل ها رو مطالعه کنم. اما الان به صورت کلی بخوام بگم حس میکنم بخاطر رها کردن TCP و استفاده از QUIC به عنوان Transport layer protocol هست که واقعا انقلابی هست. بنظرم این حرکت به اندازه منتشر شدن HTTP/1.1 در سال 1999 انقلابی هست.
یک نکته دیگ هم وجود داره که هنوز ما HTTP/3 رو روی #NodeJS std نداریم. چطور WebTransport رو اوردن نمیدونم و کنجکاوی خودم هم هست. البته شاید از پکیج H3 استفاده کردن که قبلا اینجا معرفی کرده بودیم یا شاید هم خودشون زدن که بعید میدونم.
هرچی هست دمشون گرم.
https://news.1rj.ru/str/NodeMaster/70
https://socket.io/docs/v4/changelog/4.7.0
👍13
فرصت شغلی
یه نیروی میدلول رو به بالا یا سنیور Node.js برای همکاری توی تیم مدیکال استوز نیاز داریم


همکاری به صورت پاره وقت/ دورکاریه

هزینه کار به صورت توافقی و ساعتی محاسبه میشه

حقوق ماهیانه با روزی حدود سه - چهار ساعت کار ۱۱-۱۵ میلیون تومان
(هزینه اشاره شده برای نیروی میدلول)
کار به صورت Part time و remote میباشد.
@hamed_ghaffarpour
Medicalstus.ir

#Work
Node Master
اگر در NodeJS برای وب سرورتون Auth service مینویسید و اگر فرایند Auth شما بر پایه password باشد. معمولا به این صورت مقایسه پسورد صورت میگیرید. if (hashed_pass_from_db === hashed_pass_from_input) { console.log("sucess") } این تکه کد یک مشکل امنیتی خطرناک…
معمولا وقتی راجع به امنیت و crypto در #NodeJS پست میزارم خیلی استقبال میشه. امروز میخوایم راجع به public key signture صحبت کنیم. با مثال میریم جلو.
import crypto from "node:crypto";

const { privateKey, publicKey } = crypto.generateKeyPairSync("rsa", {
modulusLength: 2048,
});

const ALGO = "RSA-SHA256";
const rawData = { username: "imanhpr", channel: "NodeMaster" };
const data = Buffer.from(JSON.stringify(rawData));

const signature = crypto.sign(ALGO, data, privateKey);

const verify = crypto.verify(ALGO, data, publicKey, signature);
console.log(verify);

در حقیقت crypto module همونطور که میدونید یک api روی Openssl هست پس ما به تمام قابلیت های openssl دسترسی داریم. حتی اگر دوست داشتید میتونید self signed tls certificate درست کنید و برای تست در web server هاتون استفاده کنید.
اینجا خیلی وارد جزیات نمیشیم و خیلی کلی گویی میشه تا طولانی نشه. جدا از encryption یک مفهوم دیگ داریم به اسم sign کردن که این دوتا معمولا در کنار هم استفاده میشن. حالا سوال پیش میاد sign چیست؟
قرار هست یک نفر یک دیتا رو برای شما ارسال کنه و میخواید مطمن بشید که فقط اون براتون فرستاده. مثل نامه های دولتی که با مهر دولتی روی نامه ثابت میشه که از طرف دولت هست و شما مطمن هستی که دولت فرستاده. حالا برای کاری شبیه به این میشه این کار رو کرد.
اول یک rsa public and private key تولید میکنید و حالا یکجایی ذخیره میکنید. با الگوریتم های دیگ هم میشه ولی خب من اینجا دوست داشتم RSA استفاده کنم.
بعد شما data خام رو بعد از serialization و encode کردن با private key ( یا همون مهر دولتی ) امضا میکنید. بعد شخصی که اونور نشسته و شما میخواید دیتا رو براش بفرستید حالا از طریق http tcp یا websocket یا هرچیزی باید public key رو داشته باشه.
شخصی که این دیتا رو دریافت کرده با استفاده از public key و verify function میتونه ثابت کنه که این دیتا توسط شما امضا شده و هیچ تغییری نکرده. دقیقا یجورایی مثل jwt token هست.
حالا این فرایند کلی بود. شما دقیقا میتونید ساختاری شبیه به jwt رو خودتون این مدلی دستی بسازید.
به طور خلاصه jwt شامل ۳ بخش با این ساختار است header.payload.signature حالا شما اگر هدر رو در نظر نگیری با استفاده از تکه کد پایین میتونین شبیه به jwt رو بسازید با ساختار payload.signature.
const jwtLike =
Buffer.from(JSON.stringify(rawData)).toString("base64") +
"." +
signature.toString("base64");
console.log(jwtLike);

این دقیق خود jwt نیست اون یکم پیچدگی بیشتر داره. ولی درکل حدف آشنایی با این موضوع بود جزیات خیلیی بیشتر بود که من واقعا خیلی خلاصه کردم و خیلی چیزا رو اصلا اشاره نکردیم که خیلی مهم بودن.
حالا در پست های آینده قطعا این موضوعات هم برسی میکنیم.

#Tip
👍10
امروز یک برنامه کلاسیک HelloWorld با استفاده از #webassembly module مینویسیم و import در #NodeJS صحبت میکنیم برای خودم خیلی باحال بود و تصور این که چه قدرتی این کار داره واقعا جذابه.
این که #NodeJS کند هست همه قبول داریم ولی خب اونقدری کند نیست که بگیم بد هست. حتی روی scale بزرگ هم جواب میده و مشکلی نیست ولی گاهی شاید بخواهیم قدرتش رو با ابزار های کمکی بیشتر کنیم. یکی از این راها استفاده از C++ N-API هست که میشه native module هایی که با CPP توسعه داده شدن رو استفاده کنیم و اصن کلا کل nodejs همین هست. تازگی ها api اومده که میتونیم کد های #rust هم bind کنیم که اسمش رو یادم نمیاد. معمولا این کارا رو زمانی انجام میدن که یک پروژه بزرگ روی nodejs هست و هزینه بازنویسی روی زبان های سریعتر مثل golang خیلی زیاد هست و ارزش نداره و با استفاده از این تکنیک ها قدرتش رو بیشتر میکنن. ( این که golang سریعتره دلیل بر بهتر بودن لزوما نیست ) از این موضوع بگذریم و بریم سر وقت مثال و کد.

اگر از #ESM استفاده میکنید قبلا بهتون گفته بودم که چطور json رو مستقیم import کنید بدون استفاده از fs.readfile و ... . یکی دیگه از ویژگی های #ESM قابلیت import کردن #WASM ماژول ها هست. WASM ها ماژول های نوشته شده با webassambly هست که سرعت near native داره که مقدمه کوچیکی بالا گفتم حالا بریم یکم مثال بزنیم. وقتی راجع به سرعت near native صحبت میکنیم شوخی نیست!
کلا با استفاده از تکنولوژی های زیادی میشه خروچی wasm گرفت از cpp و rust گرفته تا #AssamblyScript که یکچیز شبیه به #TypeScript هست ولی در اینجا ما از فرمتی به اسم #WAT یا که میشه WebAssambly Text Format استفاده میکنیم برای برنامه HelloWorld. حالا بریم با مثال صحبت کنیم.
(module
(memory 1)

(export "memory" (memory 0))
(data (i32.const 0) "Hello, World!\n\00")
(func (export "getTextOffset") (result i32)
i32.const 14
return
)
)

جدا از syntax یکی از بزرگترین چالش هایی که اینجا داریم Memory management هست که در خام ترین حالت ممکن هست تقریبا و اصلا نمیشه اینجا کوچک ترین اشاره به جزیاتش کرد ولی خب خط اول (memory 1) به مقدار 64Kib یعنی 65536 حافظه خطی در اختیار شما قرار میده. (چالش اصلی همین خطی بودن حافظه و manage کردنش برای دیتا های دیگس.
حالا با استفاده از export memory خط بعد این قسمت از حافظه رو که از WebAssembly.Memory برای دسترسی در کد #nodejs میایم و export میکنیم.
بعد با استفاده از data روی خونه اول حافظه شروع میکنیم به نوشتن بایت های helloworld و مهمترین و جذاب ترین قسمتش که کنجکاوی به وجود میاره استفاده از "\00". اینجا میخوام یک سوال مطرح کنم برام توی کامنت بگید که چرا از "\00" استفاده شده ؟
بعد میایم یک فانکشن تعریف میکنیم که یک عدد i32 برمیگردونیم که آدرس اخرین خونه ای هست که hello world داخلش قرار داره یعنی از 0 شروع شده تا 14.
حالا باید این رو compile کنیم به wasm که ابزار های مختلف هست. میتونید این کد رو کپی کنید و از سایت https://webassembly.github.io/wabt/demo/wat2wasm/ استفاده کنید برای تست و خروجی wasm رو بگیرید.
حالا آمده ایم بریم برای بخش node.
import * as mywasm from "./mywasm.wasm";

const buf = Buffer.from(mywasm.memory.buffer);

const helloWorld = buf.subarray(0, mywasm.getTextOffset());

console.log(helloWorld.toString("utf-8"));

ماژول کامپایل شده رو import میکنیم و دوتا export در کد wat میبینید. یکی memory که حافظه خام ما هست که تبدیل میکنیم به buffer ( بدون تبدیل هم میشد این کارا رو کرد ولی حال نداشتم :) )
بعد این buf ما 64kib هست درصورتی که ما فقط 14 byte از این رو میخوایم. با استفاده از export دوم یعنی فانکشن getTextOffset میایم این buf رو قیچی میکنیم و 14 byte که حاوی helloworld ما هست میگیریم و بعد با encode کردن به utf8 لاگ میگریم و تمام. حالا برای ران کردن میتونید این کار کنید.
node --experimental-wasm-modules main.js


دوستان توجه کنیدکه خیلی خیلی خلاصه کردم از اتفاق هایی که میوفته تا کوتاه بشه ولی زیر به صورت تیتر وار میگم.
- اول درمورد memory این که حالا برنامه ما اینجا کوچیک بود و زیاد مهم نیست ولی این که 64kib مموری بگیری و از 14 byte فقط استفاده کنی اصلا کار درستی نیست.
- دوم کلا حواسمون باید خیلی به encode شدن باید باشه
- سوم همون سوالی که بالا گفتم بهش فکر کنید
- چهارم اون خط تبدیل کردن به buffer نیاز نیست و راه های بهتری هست که وقت نداشتم برم دنبالشون و هدف فقط اشاره به این تکنولوژی بود.
👍6
نکته خیلی مهم این که من هم wasm بلد نیستم و برای این هم وقت زیادی نزاشتم. در آینده بیشتر روی این تکنولوژی کار میکنم و کلا یک پست هم خواهیم داشت درمورد آینده و تحلیلی که من دارم درمورد چنتا تکنولوژی و اتفاق های اخیر در کل اکوسیستم.

#Tip #WebAssembly
👍1