ΠΠ° ΡΠ°Π·Π»ΠΈΠΊΡ ΠΎΠ΄ ΡΠΎΠ±ΠΈΡΠ°ΡΠ΅Π½Π΅ Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ΅ βΠΊΠ»ΠΈΡΠ΅Π½Ρ-ΡΠ΅ΡΠ²Π΅Ρβ, Π΄Π΅ΡΠ΅Π½ΡΡΠ°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π΅ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ΅ ΠΊΠ°ΡΠ°ΠΊΡΠ΅ΡΠΈΡΠ΅:
- ΠΠ΅ΠΌΠ° ΠΏΠΎΡΡΠ΅Π±Π΅ Π·Π° ΡΠΊΠ»Π°Π΄ΠΈΡΡΠ΅ΡΠ΅ΠΌ Π±Π°Π·Π΅ ΠΏΠΎΠ΄Π°ΡΠ°ΠΊΠ° ΡΠ° ΠΊΠΎΡΠΈΡΠ½ΠΈΡΠΊΠΈΠΌ ΠΏΡΠΈΡΠ°Π²Π°ΠΌΠ° ΠΈ Π»ΠΎΠ·ΠΈΠ½ΠΊΠ°ΠΌΠ°. ΠΡΠΈΡΡΡΠΏΠ½Π΅ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡΠ΅ ΡΡΠ²Π°ΡΡ ΠΈΡΠΊΡΡΡΠΈΠ²ΠΎ ΡΠ°ΠΌΠΈ ΠΊΠΎΡΠΈΡΠ½ΠΈΡΠΈ, Π° ΠΏΠΎΡΠ²ΡΠ΄Π° ΡΠΈΡ ΠΎΠ²Π΅ Π°ΡΡΠ΅Π½ΡΠΈΡΠ½ΠΎΡΡΠΈ ΡΠ΅ Π΄Π΅ΡΠ°Π²Π° Π½Π° Π½ΠΈΠ²ΠΎΡ ΠΏΡΠΎΡΠΎΠΊΠΎΠ»Π°.
- ΠΠ΅ΠΌΠ° ΠΏΠΎΡΡΠ΅Π±Π΅ Π΄Π° ΠΊΠΎΡΠΈΡΡΠΈΡΠ΅ ΡΠ΅ΡΠ²Π΅Ρ. ΠΠΎΠ³ΠΈΠΊΠ° Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ΅ ΡΠ΅ ΠΌΠΎΠΆΠ΅ ΠΈΠ·Π²ΡΡΠΈΡΠΈ Π½Π° Π±Π»ΠΎΠΊΡΠ΅ΡΠ½ ΠΌΡΠ΅ΠΆΠΈ, Π³Π΄Π΅ ΡΠ΅ ΠΌΠΎΠ³ΡΡΠ΅ ΡΡΠΊΠ»Π°Π΄ΠΈΡΡΠΈΡΠΈ ΠΏΠΎΡΡΠ΅Π±Π½Ρ ΠΊΠΎΠ»ΠΈΡΠΈΠ½Ρ ΠΏΠΎΠ΄Π°ΡΠ°ΠΊΠ°.
ΠΠΎΡΡΠΎΡΠ΅ 2 ΡΠ΅Π»Π°ΡΠΈΠ²Π½ΠΎ Π±Π΅Π·Π±Π΅Π΄Π½Π° ΡΠΊΠ»Π°Π΄ΠΈΡΡΠ° Π·Π° ΠΊΠΎΡΠΈΡΠ½ΠΈΡΠΊΠ΅ ΠΊΡΡΡΠ΅Π²Π΅ - Ρ Π°ΡΠ΄Π²Π΅ΡΡΠΊΠΈ Π½ΠΎΠ²ΡΠ°Π½ΠΈΡΠΈ ΠΈ Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠ΅ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ°. Π₯Π°ΡΠ΄Π²Π΅ΡΡΠΊΠΈ Π½ΠΎΠ²ΡΠ°Π½ΠΈΡΠΈ ΡΡ ΡΠ³Π»Π°Π²Π½ΠΎΠΌ ΠΈΠ·ΡΠ·Π΅ΡΠ½ΠΎ Π±Π΅Π·Π±Π΅Π΄Π½ΠΈ, Π°Π»ΠΈ ΡΠ΅ΡΠΊΠΈ Π·Π° ΠΊΠΎΡΠΈΡΡΠ΅ΡΠ΅ ΠΈ Π΄Π°Π»Π΅ΠΊΠΎ ΠΎΠ΄ Π±Π΅ΡΠΏΠ»Π°ΡΠ½ΠΈΡ , Π°Π»ΠΈ ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ° ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ° ΡΡ ΡΠ°Π²ΡΡΠ΅Π½Π° ΠΊΠΎΠΌΠ±ΠΈΠ½Π°ΡΠΈΡΠ° Π±Π΅Π·Π±Π΅Π΄Π½ΠΎΡΡΠΈ ΠΈ Π»Π°ΠΊΠΎΡΠ΅ ΠΊΠΎΡΠΈΡΡΠ΅ΡΠ°, Π° ΠΌΠΎΠ³Ρ Π±ΠΈΡΠΈ ΠΈ ΠΏΠΎΡΠΏΡΠ½ΠΎ Π±Π΅ΡΠΏΠ»Π°ΡΠ½Π° Π·Π° ΠΊΡΠ°ΡΡΠ΅ ΠΊΠΎΡΠΈΡΠ½ΠΈΠΊΠ΅.
Π£Π·ΠΈΠΌΠ°ΡΡΡΠΈ ΡΠ²Π΅ ΠΎΠ²ΠΎ Ρ ΠΎΠ±Π·ΠΈΡ, ΠΆΠ΅Π»Π΅Π»ΠΈ ΡΠΌΠΎ Π΄Π° Π½Π°ΠΏΡΠ°Π²ΠΈΠΌΠΎ Π½Π°ΡΠ±Π΅Π·Π±Π΅Π΄Π½ΠΈΡΠ΅ ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ΅ ΠΊΠΎΡΠ΅ ΠΏΠΎΡΠ΅Π΄Π½ΠΎΡΡΠ°Π²ΡΡΡΠ΅ ΡΠ°Π·Π²ΠΎΡ Π΄Π΅ΡΠ΅Π½ΡΡΠ°Π»ΠΈΠ·ΠΎΠ²Π°Π½ΠΈΡ
Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ° ΠΏΡΡΠΆΠ°ΡΠ΅ΠΌ ΡΠ΅Π΄Π½ΠΎΡΡΠ°Π²Π½ΠΎΠ³ ΠΠΠ-ΡΠ° Π·Π° ΡΠ°Π΄ ΡΠ° ΡΡΠ°Π½ΡΠ°ΠΊΡΠΈΡΠ°ΠΌΠ° ΠΈ ΠΏΠΎΡΠΏΠΈΡΠΈΠΌΠ°.
Π ΠΎΠ²ΠΎΠΌ ΠΈΡΠΊΡΡΡΠ²Ρ ΡΠ΅ΠΌΠΎ Π²Π°ΠΌ ΡΠ΅ΡΠΈ Ρ Π½Π°ΡΡΠ°Π²ΠΊΡ.
Π§Π»Π°Π½Π°ΠΊ ΡΠ΅ ΡΠ°Π΄ΡΠΆΠ°ΡΠΈ ΡΠΏΡΡΡΡΠ²Π° ΠΊΠΎΡΠ°ΠΊ ΠΏΠΎ ΠΊΠΎΡΠ°ΠΊ ΠΎ ΡΠΎΠΌΠ΅ ΠΊΠ°ΠΊΠΎ Π½Π°ΠΏΠΈΡΠ°ΡΠΈ ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ΅ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ°, ΡΠ° ΠΏΡΠΈΠΌΠ΅ΡΠΈΠΌΠ° ΠΊΠΎΠ΄Π° ΠΈ ΡΠ½ΠΈΠΌΡΠΈΠΌΠ° Π΅ΠΊΡΠ°Π½Π°. ΠΠΎΠΆΠ΅ΡΠ΅ ΠΏΡΠΎΠ½Π°ΡΠΈ ΡΠ°Π² ΠΊΠΎΠ΄ Ρ
ΠΡΠ°ΡΠΊΠ° ΠΈΡΡΠΎΡΠΈΡΠ° ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ° ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ°
ΠΠΊΡΡΠ΅Π½Π·ΠΈΡΠ΅ Π·Π° ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ΅ ΠΏΠΎΡΡΠΎΡΠ΅ Π²Π΅Ρ Π΄ΡΠΆΠ΅ Π²ΡΠ΅ΠΌΠ΅. ΠΠΎΡΠ°Π²ΠΈΠ»ΠΈ ΡΡ ΡΠ΅ Ρ ΠΠ½ΡΠ΅ΡΠ½Π΅Ρ ΠΠΊΠΏΠ»ΠΎΡΠ΅Ρ-Ρ ΡΠΎΡ 1999. Π³ΠΎΠ΄ΠΈΠ½Π΅, Ρ Π€ΠΈΡΠ΅ΡΠΎΠΊ-Ρ 2004. Π³ΠΎΠ΄ΠΈΠ½Π΅. ΠΠ΅ΡΡΡΠΈΠΌ, Π²Π΅ΠΎΠΌΠ° Π΄ΡΠ³ΠΎ Π½ΠΈΡΠ΅ ΠΏΠΎΡΡΠΎΡΠ°ΠΎ ΡΠ΅Π΄ΠΈΠ½ΡΡΠ²Π΅Π½ΠΈ ΡΡΠ°Π½Π΄Π°ΡΠ΄ Π·Π° ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ°.
ΠΠΎΠΆΠ΅ΠΌΠΎ ΡΠ΅ΡΠΈ Π΄Π° ΡΠ΅ ΠΏΠΎΡΠ°Π²ΠΈΠΎ Π·Π°ΡΠ΅Π΄Π½ΠΎ ΡΠ° Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠ°ΠΌΠ° Ρ ΡΠ΅ΡΠ²ΡΡΠΎΡ Π²Π΅ΡΠ·ΠΈΡΠΈ ΠΠΎΠΎΠ³Π»Π΅ Π¦Ρ ΡΠΎΠΌΠ΅-Π°. ΠΠ°ΡΠ°Π²Π½ΠΎ, ΡΠ°Π΄Π° Π½ΠΈΡΠ΅ Π±ΠΈΠ»ΠΎ ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡΠ΅, Π°Π»ΠΈ ΡΠ΅ Π¦Ρ ΡΠΎΠΌΠ΅ ΠΠΠ ΠΏΠΎΡΡΠ°ΠΎ ΡΠ΅Π³ΠΎΠ²Π° ΠΎΡΠ½ΠΎΠ²Π°: ΠΎΡΠ²ΠΎΡΠΈΠ²ΡΠΈ Π²Π΅ΡΠΈΠ½Ρ ΡΡΠΆΠΈΡΡΠ° ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ° ΠΈ ΠΈΠΌΠ°ΡΡΡΠΈ ΡΠ³ΡΠ°ΡΠ΅Π½Ρ ΠΏΡΠΎΠ΄Π°Π²Π½ΠΈΡΡ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ°, Π¦Ρ ΡΠΎΠΌΠ΅ ΡΠ΅ Π·Π°ΠΏΡΠ°Π²ΠΎ ΠΏΠΎΡΡΠ°Π²ΠΈΠΎ ΡΡΠ°Π½Π΄Π°ΡΠ΄ Π·Π° ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ° ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ°.
ΠΠΎΠ·ΠΈΠ»Π»Π° ΡΠ΅ ΠΈΠΌΠ°Π»Π° ΡΠ²ΠΎΡ ΡΡΠ°Π½Π΄Π°ΡΠ΄, Π°Π»ΠΈ Π²ΠΈΠ΄Π΅Π²ΡΠΈ ΠΏΠΎΠΏΡΠ»Π°ΡΠ½ΠΎΡΡ Π¦Ρ ΡΠΎΠΌΠ΅ Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠ°, ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΡΠ° ΡΠ΅ ΠΎΠ΄Π»ΡΡΠΈΠ»Π° Π΄Π° Π½Π°ΠΏΡΠ°Π²ΠΈ ΠΊΠΎΠΌΠΏΠ°ΡΠΈΠ±ΠΈΠ»Π°Π½ ΠΠΠ. Π£ 2015. Π³ΠΎΠ΄ΠΈΠ½ΠΈ, Π½Π° ΠΈΠ½ΠΈΡΠΈΡΠ°ΡΠΈΠ²Ρ ΠΠΎΠ·ΠΈΠ»Π΅, ΡΡΠ²ΠΎΡΠ΅Π½Π° ΡΠ΅ ΠΏΠΎΡΠ΅Π±Π½Π° Π³ΡΡΠΏΠ° Ρ ΠΎΠΊΠ²ΠΈΡΡ ΠΠΎΡΠ»Π΄ ΠΠΈΠ΄Π΅ ΠΠ΅Π± Π¦ΠΎΠ½ΡΠΎΡΡΠΈΡΠΌ (Π3Π¦) Π·Π° ΡΠ°Π΄ Π½Π° ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡΠ°ΠΌΠ° ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ° Π·Π° Π²ΠΈΡΠ΅ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ°.
ΠΠΎΡΡΠΎΡΠ΅ΡΠ° ΠΠΠ ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ° Π·Π° Π¦Ρ
ΡΠΎΠΌΠ΅ ΡΡ ΡΠ·Π΅ΡΠ° ΠΊΠ°ΠΎ ΠΎΡΠ½ΠΎΠ²Π°. Π Π°Π΄ ΡΠ΅ ΠΎΠ±Π°Π²ΡΠ΅Π½ ΡΠ· ΠΏΠΎΠ΄ΡΡΠΊΡ ΠΠΈΡΡΠΎΡΠΎΡΡΠ° (ΠΡΠ³Π» ΡΠ΅ ΠΎΠ΄Π±ΠΈΠΎ Π΄Π° ΡΡΠ΅ΡΡΠ²ΡΡΠ΅ Ρ ΡΠ°Π·Π²ΠΎΡΡ ΡΡΠ°Π½Π΄Π°ΡΠ΄Π°), Π° ΠΊΠ°ΠΎ ΡΠ΅Π·ΡΠ»ΡΠ°Ρ ΡΠΎΠ³Π° ΠΏΠΎΡΠ°Π²ΠΈΠΎ ΡΠ΅ Π½Π°ΡΡΡ
Π€ΠΎΡΠΌΠ°Π»Π½ΠΎ, ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡΡ ΠΏΠΎΠ΄ΡΠΆΠ°Π²Π°ΡΡ ΠΠ΄Π³Π΅, Π€ΠΈΡΠ΅ΡΠΎΠΊ ΠΈ ΠΠΏΠ΅ΡΠ° (ΠΈΠΌΠ°ΡΡΠ΅ Π½Π° ΡΠΌΡ Π΄Π° Π¦Ρ
ΡΠΎΠΌΠ΅ Π½ΠΈΡΠ΅ Π½Π° ΠΎΠ²ΠΎΡ Π»ΠΈΡΡΠΈ). ΠΠ»ΠΈ Ρ ΡΡΠ²Π°ΡΠΈ, ΡΡΠ°Π½Π΄Π°ΡΠ΄ ΡΠ΅ Ρ Π²Π΅Π»ΠΈΠΊΠΎΡ ΠΌΠ΅ΡΠΈ ΠΊΠΎΠΌΠΏΠ°ΡΠΈΠ±ΠΈΠ»Π°Π½ ΡΠ° Π¦Ρ
ΡΠΎΠΌΠ΅-ΠΎΠΌ, ΠΏΠΎΡΡΠΎ ΡΠ΅ Π·Π°ΠΏΡΠ°Π²ΠΎ Π½Π°ΠΏΠΈΡΠ°Π½ Π½Π° ΠΎΡΠ½ΠΎΠ²Ρ ΡΠ΅Π³ΠΎΠ²ΠΈΡ
Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠ°. ΠΠΎΠΆΠ΅ΡΠ΅ ΠΏΡΠΎΡΠΈΡΠ°ΡΠΈ Π²ΠΈΡΠ΅ ΠΎ ΠΠ΅Π±ΠΠΊΡΠ΅Π½ΡΠΈΠΎΠ½Ρ ΠΠΠ-ΡΡ
Π‘ΡΡΡΠΊΡΡΡΠ° ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ°
ΠΠ΅Π΄ΠΈΠ½Π° Π΄Π°ΡΠΎΡΠ΅ΠΊΠ° ΠΊΠΎΡΠ° ΡΠ΅ ΠΏΠΎΡΡΠ΅Π±Π½Π° Π·Π° Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΡ ΡΠ΅ ΠΌΠ°Π½ΠΈΡΠ΅ΡΡ (ΠΌΠ°Π½ΠΈΡΠ΅ΡΡ.ΡΡΠΎΠ½). Π’ΠΎ ΡΠ΅ ΡΠ°ΠΊΠΎΡΠ΅ βΡΠ»Π°Π·Π½Π° ΡΠ°ΡΠΊΠ°β Ρ ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ΅.
ΠΠ°Π½ΠΈΡΠ΅ΡΡ
ΠΡΠ΅ΠΌΠ° ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡΠΈ, Π΄Π°ΡΠΎΡΠ΅ΠΊΠ° ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΠ° ΡΠ΅ Π²Π°ΠΆΠ΅ΡΠ° ΠΠ‘ΠΠ Π΄Π°ΡΠΎΡΠ΅ΠΊΠ°. ΠΠΎΡΠΏΡΠ½ΠΈ ΠΎΠΏΠΈΡ ΠΊΡΡΡΠ΅Π²Π° ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΠ° ΡΠ° ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡΠ°ΠΌΠ° ΠΎ ΡΠΎΠΌΠ΅ ΠΊΠΎΡΠΈ ΠΊΡΡΡΠ΅Π²ΠΈ ΡΡ ΠΏΠΎΠ΄ΡΠΆΠ°Π½ΠΈ Ρ ΠΊΠΎΠΌ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΡ ΡΠ΅ ΠΌΠΎΠΆΠ΅ Π²ΠΈΠ΄Π΅ΡΠΈ
ΠΡΡΡΠ΅Π²ΠΈ ΠΊΠΎΡΠΈ Π½ΠΈΡΡ Ρ ΡΠΏΠ΅ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡΠΈ βΠΌΠΎΠ³Ρβ Π±ΠΈΡΠΈ Π·Π°Π½Π΅ΠΌΠ°ΡΠ΅Π½ΠΈ (ΠΈ Π¦Ρ ΡΠΎΠΌΠ΅ ΠΈ Π€ΠΈΡΠ΅ΡΠΎΠΊ ΠΏΡΠΈΡΠ°Π²ΡΡΡΡ Π³ΡΠ΅ΡΠΊΠ΅, Π°Π»ΠΈ Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠ΅ Π½Π°ΡΡΠ°Π²ΡΠ°ΡΡ Π΄Π° ΡΠ°Π΄Π΅).
Π ΠΆΠ΅Π»Π΅ΠΎ Π±ΠΈΡ Π΄Π° ΡΠΊΡΠ΅Π½Π΅ΠΌ ΠΏΠ°ΠΆΡΡ Π½Π° Π½Π΅ΠΊΠ΅ ΡΠ°ΡΠΊΠ΅.
- ΠΏΠΎΠ·Π°Π΄ΠΈΠ½Π° β ΠΎΠ±ΡΠ΅ΠΊΠ°Ρ ΠΊΠΎΡΠΈ ΡΠΊΡΡΡΡΡΠ΅ ΡΠ»Π΅Π΄Π΅ΡΠ° ΠΏΠΎΡΠ°:
- ΡΠΊΡΠΈΠΏΡΠ΅ β Π½ΠΈΠ· ΡΠΊΡΠΈΠΏΡΠΈ ΠΊΠΎΡΠ΅ ΡΠ΅ ΡΠ΅ ΠΈΠ·Π²ΡΡΠ°Π²Π°ΡΠΈ Ρ ΠΏΠΎΠ·Π°Π΄ΠΈΠ½ΡΠΊΠΎΠΌ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΡ (ΠΎ ΡΠΎΠΌΠ΅ ΡΠ΅ΠΌΠΎ Π³ΠΎΠ²ΠΎΡΠΈΡΠΈ ΠΌΠ°Π»ΠΎ ΠΊΠ°ΡΠ½ΠΈΡΠ΅);
- ΡΡΡΠ°Π½Π° - ΡΠΌΠ΅ΡΡΠΎ ΡΠΊΡΠΈΠΏΡΠΈ ΠΊΠΎΡΠ΅ ΡΠ΅ ΡΠ΅ ΠΈΠ·Π²ΡΡΠ°Π²Π°ΡΠΈ Π½Π° ΠΏΡΠ°Π·Π½ΠΎΡ ΡΡΡΠ°Π½ΠΈΡΠΈ, ΠΌΠΎΠΆΠ΅ΡΠ΅ Π½Π°Π²Π΅ΡΡΠΈ Ρ ΡΠΌΠ» ΡΠ° ΡΠ°Π΄ΡΠΆΠ°ΡΠ΅ΠΌ. Π£ ΠΎΠ²ΠΎΠΌ ΡΠ»ΡΡΠ°ΡΡ, ΠΏΠΎΡΠ΅ ΡΠΊΡΠΈΠΏΡΠ΅ ΡΠ΅ Π±ΠΈΡΠΈ Π·Π°Π½Π΅ΠΌΠ°ΡΠ΅Π½ΠΎ, Π° ΡΠΊΡΠΈΠΏΡΠ΅ ΡΠ΅ ΠΌΠΎΡΠ°ΡΠΈ Π΄Π° ΡΠ΅ ΡΠ±Π°ΡΠ΅ Ρ ΡΡΡΠ°Π½ΠΈΡΡ ΡΠ° ΡΠ°Π΄ΡΠΆΠ°ΡΠ΅ΠΌ;
- ΡΠΏΠΎΡΠ°Π½ β Π±ΠΈΠ½Π°ΡΠ½Π° Π·Π°ΡΡΠ°Π²ΠΈΡΠ°, Π°ΠΊΠΎ Π½ΠΈΡΠ΅ Π½Π°Π²Π΅Π΄Π΅Π½Π°, ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°Ρ ΡΠ΅ βΡΠ±ΠΈΡΠΈβ ΠΏΠΎΠ·Π°Π΄ΠΈΠ½ΡΠΊΠΈ ΠΏΡΠΎΡΠ΅Ρ ΠΊΠ°Π΄Π° ΡΠΌΠ°ΡΡΠ° Π΄Π° Π½Π΅ ΡΠ°Π΄ΠΈ Π½ΠΈΡΡΠ° ΠΈ ΠΏΠΎΠ½ΠΎΠ²ΠΎ Π³Π° ΠΏΠΎΠΊΡΠ΅Π½ΡΡΠΈ Π°ΠΊΠΎ ΡΠ΅ ΠΏΠΎΡΡΠ΅Π±Π½ΠΎ. Π£ ΡΡΠΏΡΠΎΡΠ½ΠΎΠΌ, ΡΡΡΠ°Π½ΠΈΡΠ° ΡΠ΅ Π±ΠΈΡΠΈ ΡΡΠΈΡΠ°Π½Π° ΡΠ°ΠΌΠΎ ΠΊΠ°Π΄Π° ΡΠ΅ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°Ρ Π·Π°ΡΠ²ΠΎΡΠ΅Π½. ΠΠΈΡΠ΅ ΠΏΠΎΠ΄ΡΠΆΠ°Π½ΠΎ Ρ Π€ΠΈΡΠ΅ΡΠΎΠΊ-Ρ.
- ΡΠΎΠ½ΡΠ΅Π½Ρ_ΡΡΡΠΈΠΏΡΡ β Π½ΠΈΠ· ΠΎΠ±ΡΠ΅ΠΊΠ°ΡΠ° ΠΊΠΎΡΠΈ Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡΡΠ°Π²Π°ΡΡ Π΄Π° ΡΡΠΈΡΠ°ΡΠ΅ ΡΠ°Π·Π»ΠΈΡΠΈΡΠ΅ ΡΠΊΡΠΈΠΏΡΠ΅ Π½Π° ΡΠ°Π·Π»ΠΈΡΠΈΡΠ΅ Π²Π΅Π± ΡΡΡΠ°Π½ΠΈΡΠ΅. Π‘Π²Π°ΠΊΠΈ ΠΎΠ±ΡΠ΅ΠΊΠ°Ρ ΡΠ°Π΄ΡΠΆΠΈ ΡΠ»Π΅Π΄Π΅ΡΠ° Π²Π°ΠΆΠ½Π° ΠΏΠΎΡΠ°:
- ΡΠΈΠ±ΠΈΡΠ΅ -
ΠΎΠ±ΡΠ°Π·Π°Ρ ΡΡΠ» , ΠΊΠΎΡΠΈ ΠΎΠ΄ΡΠ΅ΡΡΡΠ΅ Π΄Π° Π»ΠΈ ΡΠ΅ ΠΎΠ΄ΡΠ΅ΡΠ΅Π½Π° ΡΠΊΡΠΈΠΏΡΠ° ΡΠ°Π΄ΡΠΆΠ°ΡΠ° Π±ΠΈΡΠΈ ΡΠΊΡΡΡΠ΅Π½Π° ΠΈΠ»ΠΈ Π½Π΅. - js β ΡΠΏΠΈΡΠ°ΠΊ ΡΠΊΡΠΈΠΏΡΠΈ ΠΊΠΎΡΠ΅ ΡΠ΅ Π±ΠΈΡΠΈ ΡΡΠΈΡΠ°Π½Π΅ Ρ ΠΎΠ²Π°Ρ ΠΌΠ΅Ρ;
- Π΅ΠΊΡΠ»ΡΠ΄Π΅_ΠΌΠ°ΡΡΡ
Π΅Ρ - ΠΈΡΠΊΡΡΡΡΡΠ΅ ΡΠ° ΡΠ΅ΡΠ΅Π½Π°
match
Π£Π Π Π°Π΄ΡΠ΅ΡΠ΅ ΠΊΠΎΡΠ΅ ΠΎΠ΄Π³ΠΎΠ²Π°ΡΠ°ΡΡ ΠΎΠ²ΠΎΠΌ ΠΏΠΎΡΡ.
- ΡΠΈΠ±ΠΈΡΠ΅ -
- ΠΏΠ°Π³Π΅_Π°ΡΡΠΈΠΎΠ½ - ΡΠ΅ Π·Π°ΠΏΡΠ°Π²ΠΎ ΠΎΠ±ΡΠ΅ΠΊΠ°Ρ ΠΊΠΎΡΠΈ ΡΠ΅ ΠΎΠ΄Π³ΠΎΠ²ΠΎΡΠ°Π½ Π·Π° ΠΈΠΊΠΎΠ½Ρ ΠΊΠΎΡΠ° ΡΠ΅ ΠΏΡΠΈΠΊΠ°Π·ΡΡΠ΅ ΠΏΠΎΡΠ΅Π΄ Π°Π΄ΡΠ΅ΡΠ½Π΅ ΡΡΠ°ΠΊΠ΅ Ρ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΡ ΠΈ ΠΈΠ½ΡΠ΅ΡΠ°ΠΊΡΠΈΡΡ ΡΠ° ΡΠΎΠΌ. Π’Π°ΠΊΠΎΡΠ΅ Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡΡΠ°Π²Π° Π΄Π° ΠΏΡΠΈΠΊΠ°ΠΆΠ΅ΡΠ΅ ΠΈΡΠΊΠ°ΡΡΡΠΈ ΠΏΡΠΎΠ·ΠΎΡ, ΠΊΠΎΡΠΈ ΡΠ΅ Π΄Π΅ΡΠΈΠ½ΠΈΡΠ°Π½ ΠΊΠΎΡΠΈΡΡΠ΅ΡΠ΅ΠΌ Π²Π°ΡΠ΅Π³ ΡΠΎΠΏΡΡΠ²Π΅Π½ΠΎΠ³ Π₯Π’ΠΠ-Π°, Π¦Π‘Π‘-Π° ΠΈ ΠΠ‘-Π°.
- Π΄Π΅ΡΠ°ΡΠ»Ρ_ΠΏΠΎΠΏΡΠΏ β ΠΏΡΡΠ°ΡΠ° Π΄ΠΎ Π₯Π’ΠΠ Π΄Π°ΡΠΎΡΠ΅ΠΊΠ΅ ΡΠ° ΠΈΡΠΊΠ°ΡΡΡΠΈΠΌ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΡΡΠΎΠΌ, ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ°Π΄ΡΠΆΠΈ Π¦Π‘Π‘ ΠΈ ΠΠ‘.
- ΠΠΎΠ·Π²ΠΎΠ»Π΅ β Π½ΠΈΠ· Π·Π° ΡΠΏΡΠ°Π²ΡΠ°ΡΠ΅ ΠΏΡΠ°Π²ΠΈΠΌΠ° ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ°. ΠΠΎΡΡΠΎΡΠ΅ 3 Π²ΡΡΡΠ΅ ΠΏΡΠ°Π²Π°, ΠΊΠΎΡΠ° ΡΡ Π΄Π΅ΡΠ°ΡΠ½ΠΎ ΠΎΠΏΠΈΡΠ°Π½Π°
ΠΎΠ²Π΄Π΅ - Π²Π΅Π±_Π°ΡΡΠ΅ΡΡΠΈΠ±Π»Π΅_ΡΠ΅ΡΠΎΡΡΡΠ΅Ρ β ΡΠ΅ΡΡΡΡΠΈ ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ° ΠΊΠΎΡΠ΅ Π²Π΅Π± ΡΡΡΠ°Π½ΠΈΡΠ° ΠΌΠΎΠΆΠ΅ Π΄Π° Π·Π°Ρ ΡΠ΅Π²Π°, Π½Π° ΠΏΡΠΈΠΌΠ΅Ρ, ΡΠ»ΠΈΠΊΠ΅, ΠΠ‘, Π¦Π‘Π‘, Π₯Π’ΠΠ Π΄Π°ΡΠΎΡΠ΅ΠΊΠ΅.
- Π΅ΠΊΡΠ΅ΡΠ½Π°Π»Π»ΠΈ_ΡΠΎΠ½Π½Π΅ΡΡΠ°Π±Π»Π΅ β ΠΎΠ²Π΄Π΅ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΅ΠΊΡΠΏΠ»ΠΈΡΠΈΡΠ½ΠΎ Π½Π°Π²Π΅ΡΡΠΈ ΠΠ-ΠΎΠ²Π΅ Π΄ΡΡΠ³ΠΈΡ Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠ° ΠΈ Π΄ΠΎΠΌΠ΅Π½Π° Π²Π΅Π± ΡΡΡΠ°Π½ΠΈΡΠ° ΡΠ° ΠΊΠΎΡΠΈΡ ΡΠ΅ ΠΌΠΎΠΆΠ΅ΡΠ΅ ΠΏΠΎΠ²Π΅Π·Π°ΡΠΈ. ΠΠΎΠΌΠ΅Π½ ΠΌΠΎΠΆΠ΅ Π±ΠΈΡΠΈ Π΄ΡΡΠ³ΠΎΠ³ Π½ΠΈΠ²ΠΎΠ° ΠΈΠ»ΠΈ Π²ΠΈΡΠ΅Π³. ΠΠ΅ ΡΠ°Π΄ΠΈ Ρ Π€ΠΈΡΠ΅ΡΠΎΠΊ-Ρ.
ΠΠΎΠ½ΡΠ΅ΠΊΡΡ ΠΈΠ·Π²ΡΡΠ΅ΡΠ°
ΠΠΊΡΡΠ΅Π½Π·ΠΈΡΠ° ΠΈΠΌΠ° ΡΡΠΈ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ° ΠΈΠ·Π²ΡΡΠ°Π²Π°ΡΠ° ΠΊΠΎΠ΄Π°, ΠΎΠ΄Π½ΠΎΡΠ½ΠΎ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ° ΡΠ΅ ΡΠ°ΡΡΠΎΡΠΈ ΠΎΠ΄ ΡΡΠΈ Π΄Π΅Π»Π° ΡΠ° ΡΠ°Π·Π»ΠΈΡΠΈΡΠΈΠΌ Π½ΠΈΠ²ΠΎΠΈΠΌΠ° ΠΏΡΠΈΡΡΡΠΏΠ° ΠΠΠ-ΡΡ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ°.
ΠΠΎΠ½ΡΠ΅ΠΊΡΡ ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ°
ΠΠ΅ΡΠΈΠ½Π° ΠΠΠ-ΡΠ° ΡΠ΅ Π΄ΠΎΡΡΡΠΏΠ½Π° ΠΎΠ²Π΄Π΅. Π£ ΠΎΠ²ΠΎΠΌ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΡ ΠΎΠ½ΠΈ "ΠΆΠΈΠ²Π΅":
- ΠΠΎΠ·Π°Π΄ΠΈΠ½ΡΠΊΠ° ΡΡΡΠ°Π½ΠΈΡΠ° β βΠ±Π°ΡΠΊΠ΅Π½Π΄β Π΄Π΅ΠΎ Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠ΅. ΠΠ°ΡΠΎΡΠ΅ΠΊΠ° ΡΠ΅ Π½Π°Π²Π΅Π΄Π΅Π½Π° Ρ ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΡ ΠΏΠΎΠΌΠΎΡΡ ΠΊΡΡΡΠ° βΠ±Π°ΡΠΊΠ³ΡΠΎΡΠ½Π΄β.
- ΠΡΠΊΠ°ΡΡΡΠ° ΡΡΡΠ°Π½ΠΈΡΠ° β ΠΈΡΠΊΠ°ΡΡΡΠ° ΡΡΡΠ°Π½ΠΈΡΠ° ΠΊΠΎΡΠ° ΡΠ΅ ΠΏΠΎΡΠ°Π²ΡΡΡΠ΅ ΠΊΠ°Π΄Π° ΠΊΠ»ΠΈΠΊΠ½Π΅ΡΠ΅ Π½Π° ΠΈΠΊΠΎΠ½Ρ ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ°. Π£ ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΡ
browser_action
->default_popup
. - ΠΡΠΈΠ»Π°Π³ΠΎΡΠ΅Π½Π° ΡΡΡΠ°Π½ΠΈΡΠ° β ΡΡΡΠ°Π½ΠΈΡΠ° ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ°, βΠΆΠΈΠ²ΠΈβ Ρ ΠΏΠΎΡΠ΅Π±Π½ΠΎΡ ΠΊΠ°ΡΡΠΈΡΠΈ ΠΏΡΠΈΠΊΠ°Π·Π°
chrome-extension://<id_ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ>/customPage.html
.
ΠΠ²Π°Ρ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡ ΠΏΠΎΡΡΠΎΡΠΈ Π½Π΅Π·Π°Π²ΠΈΡΠ½ΠΎ ΠΎΠ΄ ΠΏΡΠΎΠ·ΠΎΡΠ° ΠΈ ΠΊΠ°ΡΡΠΈΡΠ° ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ°. ΠΠΎΠ·Π°Π΄ΠΈΠ½ΡΠΊΠ° ΡΡΡΠ°Π½ΠΈΡΠ° ΠΏΠΎΡΡΠΎΡΠΈ Ρ ΡΠ΅Π΄Π½ΠΎΡ ΠΊΠΎΠΏΠΈΡΠΈ ΠΈ ΡΠ²Π΅ΠΊ ΡΠ°Π΄ΠΈ (ΠΈΠ·ΡΠ·Π΅ΡΠ°ΠΊ ΡΠ΅ ΡΡΡΠ°Π½ΠΈΡΠ° Π΄ΠΎΠ³Π°ΡΠ°ΡΠ°, ΠΊΠ°Π΄Π° ΡΠ΅ ΠΏΠΎΠ·Π°Π΄ΠΈΠ½ΡΠΊΠ° ΡΠΊΡΠΈΠΏΡΠ° ΠΏΠΎΠΊΡΠ΅Π½ΡΡΠ° Π΄ΠΎΠ³Π°ΡΠ°ΡΠ΅ΠΌ ΠΈ βΡΠΌΡΠ΅β Π½Π°ΠΊΠΎΠ½ ΡΠ΅Π³ΠΎΠ²ΠΎΠ³ ΠΈΠ·Π²ΡΡΠ΅ΡΠ°). ΠΡΠΊΠ°ΡΡΡΠ° ΡΡΡΠ°Π½ΠΈΡΠ° ΠΏΠΎΡΡΠΎΡΠΈ ΠΊΠ°Π΄Π° ΡΠ΅ ΠΈΡΠΊΠ°ΡΡΡΠΈ ΠΏΡΠΎΠ·ΠΎΡ ΠΎΡΠ²ΠΎΡΠ΅Π½, ΠΈ ΠΡΠΈΠ»Π°Π³ΠΎΡΠ΅Π½Π° ΡΡΡΠ°Π½ΠΈΡΠ° β Π΄ΠΎΠΊ ΡΠ΅ ΠΊΠ°ΡΡΠΈΡΠ° ΡΠ° ΡΠΎΠΌ ΠΎΡΠ²ΠΎΡΠ΅Π½Π°. ΠΠ΅ΠΌΠ° ΠΏΡΠΈΡΡΡΠΏΠ° Π΄ΡΡΠ³ΠΈΠΌ ΠΊΠ°ΡΡΠΈΡΠ°ΠΌΠ° ΠΈ ΡΠΈΡ ΠΎΠ²ΠΎΠΌ ΡΠ°Π΄ΡΠΆΠ°ΡΡ ΠΈΠ· ΠΎΠ²ΠΎΠ³ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ°.
ΠΠΎΠ½ΡΠ΅ΠΊΡΡ ΡΠΊΡΠΈΠΏΡΠ΅ ΡΠ°Π΄ΡΠΆΠ°ΡΠ°
ΠΠ°ΡΠΎΡΠ΅ΠΊΠ° ΡΠΊΡΠΈΠΏΡΠ΅ ΡΠ°Π΄ΡΠΆΠ°ΡΠ° ΡΠ΅ ΠΏΠΎΠΊΡΠ΅ΡΠ΅ Π·Π°ΡΠ΅Π΄Π½ΠΎ ΡΠ° ΡΠ²Π°ΠΊΠΎΠΌ ΠΊΠ°ΡΡΠΈΡΠΎΠΌ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ°. ΠΠΌΠ° ΠΏΡΠΈΡΡΡΠΏ Π΄Π΅Π»Ρ ΠΠΠ-ΡΠ° Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠ΅ ΠΈ ΠΠΠ ΡΡΠ°Π±Π»Ρ Π²Π΅Π± ΡΡΡΠ°Π½ΠΈΡΠ΅. ΠΠ° ΠΈΠ½ΡΠ΅ΡΠ°ΠΊΡΠΈΡΡ ΡΠ° ΡΡΡΠ°Π½ΠΈΡΠΎΠΌ ΠΎΠ΄Π³ΠΎΠ²ΠΎΡΠ½Π΅ ΡΡ ΡΠΊΡΠΈΠΏΡΠ΅ ΡΠ°Π΄ΡΠΆΠ°ΡΠ°. ΠΠΊΡΡΠ΅Π½Π·ΠΈΡΠ΅ ΠΊΠΎΡΠ΅ ΠΌΠ°Π½ΠΈΠΏΡΠ»ΠΈΡΡ ΠΠΠ ΡΡΠ°Π±Π»ΠΎΠΌ ΡΠΎ ΡΠ°Π΄Π΅ Ρ ΡΠΊΡΠΈΠΏΡΠ°ΠΌΠ° ΡΠ°Π΄ΡΠΆΠ°ΡΠ° β Π½Π° ΠΏΡΠΈΠΌΠ΅Ρ, Π±Π»ΠΎΠΊΠ°ΡΠΎΡΠΈΠΌΠ° ΠΎΠ³Π»Π°ΡΠ° ΠΈΠ»ΠΈ ΠΏΡΠ΅Π²ΠΎΠ΄ΠΈΠΎΡΠΈΠΌΠ°. Π’Π°ΠΊΠΎΡΠ΅, ΡΠΊΡΠΈΠΏΡΠ° ΡΠ°Π΄ΡΠΆΠ°ΡΠ° ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΊΠΎΠΌΡΠ½ΠΈΡΠΈΡΠ° ΡΠ° ΡΡΡΠ°Π½ΠΈΡΠΎΠΌ ΠΏΡΡΠ΅ΠΌ ΡΡΠ°Π½Π΄Π°ΡΠ΄Π° postMessage
.
ΠΠΎΠ½ΡΠ΅ΠΊΡΡ Π²Π΅Π± ΡΡΡΠ°Π½ΠΈΡΠ΅
ΠΠ²ΠΎ ΡΠ΅ ΡΠ°ΠΌΠ° Π²Π΅Π± ΡΡΡΠ°Π½ΠΈΡΠ°. ΠΠ΅ΠΌΠ° Π½ΠΈΠΊΠ°ΠΊΠ²Π΅ Π²Π΅Π·Π΅ ΡΠ° Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠΎΠΌ ΠΈ Π½Π΅ΠΌΠ° ΠΏΡΠΈΡΡΡΠΏ ΡΠ°ΠΌΠΎ, ΠΎΡΠΈΠΌ Ρ ΡΠ»ΡΡΠ°ΡΠ΅Π²ΠΈΠΌΠ° ΠΊΠ°Π΄Π° Π΄ΠΎΠΌΠ΅Π½ ΠΎΠ²Π΅ ΡΡΡΠ°Π½ΠΈΡΠ΅ Π½ΠΈΡΠ΅ Π΅ΠΊΡΠΏΠ»ΠΈΡΠΈΡΠ½ΠΎ Π½Π°Π²Π΅Π΄Π΅Π½ Ρ ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΡ (Π²ΠΈΡΠ΅ ΠΎ ΡΠΎΠΌΠ΅ Ρ Π½Π°ΡΡΠ°Π²ΠΊΡ).
Π Π°Π·ΠΌΠ΅Π½Π° ΠΏΠΎΡΡΠΊΠ°
Π Π°Π·Π»ΠΈΡΠΈΡΠΈ Π΄Π΅Π»ΠΎΠ²ΠΈ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ΅ ΠΌΠΎΡΠ°ΡΡ ΠΌΠ΅ΡΡΡΠΎΠ±Π½ΠΎ Π΄Π° ΡΠ°Π·ΠΌΠ΅ΡΡΡΡ ΠΏΠΎΡΡΠΊΠ΅. ΠΠ° ΠΎΠ²ΠΎ ΠΏΠΎΡΡΠΎΡΠΈ ΠΠΠ runtime.sendMessage
Π΄Π° ΠΏΠΎΡΠ°ΡΠ΅ΡΠ΅ ΠΏΠΎΡΡΠΊΡ background
ΠΈ tabs.sendMessage
Π΄Π° ΠΏΠΎΡΠ°ΡΠ΅ΡΠ΅ ΠΏΠΎΡΡΠΊΡ ΡΡΡΠ°Π½ΠΈΡΠΈ (ΡΠΊΡΠΈΠΏΡΠ° ΡΠ°Π΄ΡΠΆΠ°ΡΠ°, ΠΈΡΠΊΠ°ΡΡΡΠΈ ΠΏΡΠΎΠ·ΠΎΡ ΠΈΠ»ΠΈ Π²Π΅Π± ΡΡΡΠ°Π½ΠΈΡΠ° Π°ΠΊΠΎ ΡΠ΅ Π΄ΠΎΡΡΡΠΏΠ½Π° externally_connectable
). ΠΡΠΏΠΎΠ΄ ΡΠ΅ ΠΏΡΠΈΠΌΠ΅Ρ ΠΊΠ°Π΄Π° ΠΏΡΠΈΡΡΡΠΏΠ°ΡΠ΅ Π¦Ρ
ΡΠΎΠΌΠ΅ ΠΠΠ-ΡΡ.
// Π‘ΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ΠΌ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ Π»ΡΠ±ΠΎΠΉ JSON ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·ΡΠ΅ΠΌΡΠΉ ΠΎΠ±ΡΠ΅ΠΊΡ
const msg = {a: 'foo', b: 'bar'};
// extensionId ΠΌΠΎΠΆΠ½ΠΎ Π½Π΅ ΡΠΊΠ°Π·ΡΠ²Π°ΡΡ, Π΅ΡΠ»ΠΈ ΠΌΡ Ρ
ΠΎΡΠΈΠΌ ΠΏΠΎΡΠ»Π°ΡΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ 'ΡΠ²ΠΎΠ΅ΠΌΡ' ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ (ΠΈΠ· ui ΠΈΠ»ΠΈ ΠΊΠΎΠ½ΡΠ΅Π½Ρ ΡΠΊΡΠΈΠΏΡΠ°)
chrome.runtime.sendMessage(extensionId, msg);
// Π’Π°ΠΊ Π²ΡΠ³Π»ΡΠ΄ΠΈΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ
chrome.runtime.onMessage.addListener((msg) => console.log(msg))
// ΠΠΎΠΆΠ½ΠΎ ΡΠ»Π°ΡΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ Π²ΠΊΠ»Π°Π΄ΠΊΠ°ΠΌ Π·Π½Π°Ρ ΠΈΡ
id
chrome.tabs.sendMessage(tabId, msg)
// ΠΠΎΠ»ΡΡΠΈΡΡ ΠΊ Π²ΠΊΠ»Π°Π΄ΠΊΠ°ΠΌ ΠΈ ΠΈΡ
id ΠΌΠΎΠΆΠ½ΠΎ, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, Π²ΠΎΡ ΡΠ°ΠΊ
chrome.tabs.query(
{currentWindow: true, active : true},
function(tabArray){
tabArray.forEach(tab => console.log(tab.id))
}
)
ΠΠ° ΠΏΠΎΡΠΏΡΠ½Ρ ΠΊΠΎΠΌΡΠ½ΠΈΠΊΠ°ΡΠΈΡΡ, ΠΌΠΎΠΆΠ΅ΡΠ΅ ΠΊΡΠ΅ΠΈΡΠ°ΡΠΈ Π²Π΅Π·Π΅ ΠΏΡΠ΅ΠΊΠΎ runtime.connect
. ΠΠ°ΠΎ ΠΎΠ΄Π³ΠΎΠ²ΠΎΡ ΡΠ΅ΠΌΠΎ Π΄ΠΎΠ±ΠΈΡΠΈ runtime.Port
, Π½Π° ΠΊΠΎΡΠΈ, Π΄ΠΎΠΊ ΡΠ΅ ΠΎΡΠ²ΠΎΡΠ΅Π½, ΠΌΠΎΠΆΠ΅ΡΠ΅ ΡΠ»Π°ΡΠΈ Π±ΠΈΠ»ΠΎ ΠΊΠΎΡΠΈ Π±ΡΠΎΡ ΠΏΠΎΡΡΠΊΠ°. ΠΠ° ΡΡΡΠ°Π½ΠΈ ΠΊΠ»ΠΈΡΠ΅Π½ΡΠ°, Π½ΠΏΡ. contentscript
, ΠΈΠ·Π³Π»Π΅Π΄Π° ΠΎΠ²Π°ΠΊΠΎ:
// ΠΠΏΡΡΡ ΠΆΠ΅ extensionId ΠΌΠΎΠΆΠ½ΠΎ Π½Π΅ ΡΠΊΠ°Π·ΡΠ²Π°ΡΡ ΠΏΡΠΈ ΠΊΠΎΠΌΠΌΡΠ½ΠΈΠΊΠ°ΡΠΈΠΈ Π²Π½ΡΡΡΠΈ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ. ΠΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΠΌΠ΅Π½ΠΎΠ²Π°ΡΡ
const port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
if (msg.question === "Who's there?")
port.postMessage({answer: "Madame"});
else if (msg.question === "Madame who?")
port.postMessage({answer: "Madame... Bovary"});
Π‘Π΅ΡΠ²Π΅Ρ ΠΈΠ»ΠΈ ΠΏΠΎΠ·Π°Π΄ΠΈΠ½Π°:
// ΠΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ Π΄Π»Ρ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΡ 'ΡΠ²ΠΎΠΈΡ
' Π²ΠΊΠ»Π°Π΄ΠΎΠΊ. ΠΠΎΠ½ΡΠ΅Π½Ρ ΡΠΊΡΠΈΠΏΡΠΎΠ², popup ΠΈΠ»ΠΈ ΡΡΡΠ°Π½ΠΈΡ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ
chrome.runtime.onConnect.addListener(function(port) {
console.assert(port.name === "knockknock");
port.onMessage.addListener(function(msg) {
if (msg.joke === "Knock knock")
port.postMessage({question: "Who's there?"});
else if (msg.answer === "Madame")
port.postMessage({question: "Madame who?"});
else if (msg.answer === "Madame... Bovary")
port.postMessage({question: "I don't get it."});
});
});
// ΠΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ Π΄Π»Ρ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΡ Π²Π½Π΅ΡΠ½ΠΈΡ
Π²ΠΊΠ»Π°Π΄ΠΎΠΊ. ΠΡΡΠ³ΠΈΡ
ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΠΉ ΠΈΠ»ΠΈ Π²Π΅Π± ΡΡΡΠ°Π½ΠΈΡ, ΠΊΠΎΡΠΎΡΡΠΌ ΡΠ°Π·ΡΠ΅ΡΠ΅Π½ Π΄ΠΎΡΡΡΠΏ Π² ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΠ΅
chrome.runtime.onConnectExternal.addListener(function(port) {
...
});
ΠΠΎΡΡΠΎΡΠΈ ΠΈ Π΄ΠΎΠ³Π°ΡΠ°Ρ onDisconnect
ΠΈ ΠΌΠ΅ΡΠΎΠ΄ disconnect
.
ΠΠΈΡΠ°Π³ΡΠ°ΠΌ ΠΏΡΠΈΠΌΠ΅Π½Π΅
Π₯Π°ΡΠ΄Π΅ Π΄Π° Π½Π°ΠΏΡΠ°Π²ΠΈΠΌΠΎ ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ΅ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ° ΠΊΠΎΡΠ΅ ΡΡΠ²Π° ΠΏΡΠΈΠ²Π°ΡΠ½Π΅ ΠΊΡΡΡΠ΅Π²Π΅, ΠΎΠΌΠΎΠ³ΡΡΠ°Π²Π° ΠΏΡΠΈΡΡΡΠΏ ΡΠ°Π²Π½ΠΈΠΌ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡΠ°ΠΌΠ° (Π°Π΄ΡΠ΅ΡΠ°, ΡΠ°Π²Π½ΠΈ ΠΊΡΡΡ ΠΊΠΎΠΌΡΠ½ΠΈΡΠΈΡΠ° ΡΠ° ΡΡΡΠ°Π½ΠΈΡΠΎΠΌ ΠΈ ΠΎΠΌΠΎΠ³ΡΡΠ°Π²Π° Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ°ΠΌΠ° ΡΡΠ΅ΡΠΈΡ ΡΡΡΠ°Π½Π° Π΄Π° Π·Π°Ρ ΡΠ΅Π²Π°ΡΡ ΠΏΠΎΡΠΏΠΈΡ Π·Π° ΡΡΠ°Π½ΡΠ°ΠΊΡΠΈΡΠ΅.
Π Π°Π·Π²ΠΎΡ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ°
ΠΠ°ΡΠ° Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ° ΠΌΠΎΡΠ° ΠΈ Π΄Π° ΠΊΠΎΠΌΡΠ½ΠΈΡΠΈΡΠ° ΡΠ° ΠΊΠΎΡΠΈΡΠ½ΠΈΠΊΠΎΠΌ ΠΈ Π΄Π° ΡΡΡΠ°Π½ΠΈΡΠΈ ΠΎΠ±Π΅Π·Π±Π΅Π΄ΠΈ ΠΠΠ Π·Π° ΠΏΠΎΠ·ΠΈΠ²Π°ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Π° (Π½Π° ΠΏΡΠΈΠΌΠ΅Ρ, Π·Π° ΠΏΠΎΡΠΏΠΈΡΠΈΠ²Π°ΡΠ΅ ΡΡΠ°Π½ΡΠ°ΠΊΡΠΈΡΠ°). ΠΠ°Π΄ΠΎΠ²ΠΎΡΠΈΡΠ΅ ΡΠ΅ ΡΠ°ΠΌΠΎ ΡΠ΅Π΄Π½ΠΈΠΌ contentscript
Π½Π΅ΡΠ΅ ΡΠ°Π΄ΠΈΡΠΈ, ΠΏΠΎΡΡΠΎ ΠΈΠΌΠ° ΠΏΡΠΈΡΡΡΠΏ ΡΠ°ΠΌΠΎ ΠΠΠ-Ρ, Π°Π»ΠΈ Π½Π΅ ΠΈ ΠΠ‘-Ρ ΡΡΡΠ°Π½ΠΈΡΠ΅. ΠΠΎΠ²Π΅ΠΆΠΈΡΠ΅ ΡΠ΅ ΠΏΡΠ΅ΠΊΠΎ runtime.connect
Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌΠΎ, ΡΠ΅Ρ ΡΠ΅ ΠΠΠ ΠΏΠΎΡΡΠ΅Π±Π°Π½ Π½Π° ΡΠ²ΠΈΠΌ Π΄ΠΎΠΌΠ΅Π½ΠΈΠΌΠ°, Π° ΡΠ°ΠΌΠΎ ΠΎΠ΄ΡΠ΅ΡΠ΅Π½ΠΈ ΠΌΠΎΠ³Ρ Π±ΠΈΡΠΈ Π½Π°Π²Π΅Π΄Π΅Π½ΠΈ Ρ ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΡ. ΠΠ°ΠΎ ΡΠ΅Π·ΡΠ»ΡΠ°Ρ, Π΄ΠΈΡΠ°Π³ΡΠ°ΠΌ ΡΠ΅ ΠΈΠ·Π³Π»Π΅Π΄Π°ΡΠΈ ΠΎΠ²Π°ΠΊΠΎ:
ΠΠΈΡΠ΅ ΡΠΎΡ ΡΠ΅Π΄Π°Π½ ΡΡΠ΅Π½Π°ΡΠΈΠΎ - inpage
, ΠΊΠΎΡΠΈ ΡΠ΅ΠΌΠΎ ΡΠ±Π°ΡΠΈΡΠΈ Π½Π° ΡΡΡΠ°Π½ΠΈΡΡ. ΠΠΎΠΊΡΠ΅ΡΠ΅ ΡΠ΅ Ρ ΡΠ²ΠΎΠΌ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΡ ΠΈ ΠΎΠ±Π΅Π·Π±Π΅Π΄ΠΈΡΠ΅ ΠΠΠ Π·Π° ΡΠ°Π΄ ΡΠ° Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠΎΠΌ.
ΠΏΠΎΡΠ΅ΡΠ°ΠΊ
Π‘Π°Π² ΠΊΠΎΠ΄ ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ° ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ° Π΄ΠΎΡΡΡΠΏΠ°Π½ ΡΠ΅ Π½Π°
ΠΠΎΡΠ½ΠΈΠΌΠΎ ΡΠ° ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΠΎΠΌ:
{
// ΠΠΌΡ ΠΈ ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅, Π²Π΅ΡΡΠΈΡ. ΠΡΠ΅ ΡΡΠΎ Π±ΡΠ΄Π΅Ρ Π²ΠΈΠ΄Π½ΠΎ Π² Π±ΡΠ°ΡΠ·Π΅ΡΠ΅ Π² chrome://extensions/?id=<id ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ>
"name": "Signer",
"description": "Extension demo",
"version": "0.0.1",
"manifest_version": 2,
// Π‘ΠΊΡΠΈΠΏΡΡ, ΠΊΠΎΡΠΎΡΡΠ΅ Π±ΡΠ΄ΡΡ ΠΈΡΠΏΠΎΠ»Π½ΡΡΡΡ Π² background, ΠΈΡ
ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ
"background": {
"scripts": ["background.js"]
},
// ΠΠ°ΠΊΠΎΠΉ html ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π΄Π»Ρ popup
"browser_action": {
"default_title": "My Extension",
"default_popup": "popup.html"
},
// ΠΠΎΠ½ΡΠ΅Π½Ρ ΡΠΊΡΠΈΠΏΡΡ.
// Π£ Π½Π°Ρ ΠΎΠ΄ΠΈΠ½ ΠΎΠ±ΡΠ΅ΠΊΡ: Π΄Π»Ρ Π²ΡΠ΅Ρ
url Π½Π°ΡΠΈΠ½Π°ΡΡΠΈΡ
ΡΡ Ρ http ΠΈΠ»ΠΈ https ΠΌΡ Π·Π°ΠΏΡΡΠΊΠ°Π΅ΠΌ
// contenscript context ΡΠΎ ΡΠΊΡΠΈΠΏΡΠΎΠΌ contentscript.js. ΠΠ°ΠΏΡΡΠΊΠ°ΡΡ ΡΡΠ°Π·Ρ ΠΏΠΎ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΠΈ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ° Π΄Π»Ρ Π²ΡΠ΅Ρ
ΡΡΠ΅ΠΉΠΌΠΎΠ²
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"js": [
"contentscript.js"
],
"run_at": "document_start",
"all_frames": true
}
],
// Π Π°Π·ΡΠ΅ΡΠ΅Π½ Π΄ΠΎΡΡΡΠΏ ΠΊ localStorage ΠΈ idle api
"permissions": [
"storage",
// "unlimitedStorage",
//"clipboardWrite",
"idle"
//"activeTab",
//"webRequest",
//"notifications",
//"tabs"
],
// ΠΠ΄Π΅ΡΡ ΡΠΊΠ°Π·ΡΠ²Π°ΡΡΡΡ ΡΠ΅ΡΡΡΡΡ, ΠΊ ΠΊΠΎΡΠΎΡΡΠΌ Π±ΡΠ΄Π΅Ρ ΠΈΠΌΠ΅ΡΡ Π΄ΠΎΡΡΡΠΏ Π²Π΅Π± ΡΡΡΠ°Π½ΠΈΡΠ°. Π’ΠΎΠ΅ΡΡΡ ΠΈΡ
ΠΌΠΎΠΆΠ½ΠΎ Π±ΡΠ΄Π΅Ρ Π·Π°ΠΏΡΠ°ΡΠΈΠ²Π°ΡΡ fetche'ΠΌ ΠΈΠ»ΠΈ ΠΏΡΠΎΡΡΠΎ xhr
"web_accessible_resources": ["inpage.js"]
}
ΠΠ°ΠΏΡΠ°Π²ΠΈΡΠ΅ ΠΏΡΠ°Π·Π°Π½ Π±Π°ΡΠΊΠ³ΡΠΎΡΠ½Π΄.ΡΡ, ΠΏΠΎΠΏΡΠΏ.ΡΡ, ΠΈΠ½ΠΏΠ°Π³Π΅.ΡΡ ΠΈ ΡΠΎΠ½ΡΠ΅Π½ΡΡΡΡΠΈΠΏΡ.ΡΡ. ΠΠΎΠ΄Π°ΠΌΠΎ ΠΏΠΎΠΏΡΠΏ.Ρ ΡΠΌΠ» - ΠΈ Π½Π°ΡΠ° Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ° ΡΠ΅ Π²Π΅Ρ ΠΌΠΎΠΆΠ΅ ΡΡΠΈΡΠ°ΡΠΈ Ρ ΠΠΎΠΎΠ³Π»Π΅ Π¦Ρ ΡΠΎΠΌΠ΅ ΠΈ ΡΠ²Π΅ΡΠΈΡΠΈ ΡΠ΅ Π΄Π° ΡΠ°Π΄ΠΈ.
ΠΠ° Π±ΠΈΡΡΠ΅ ΡΠΎ ΠΏΠΎΡΠ²ΡΠ΄ΠΈΠ»ΠΈ, ΠΌΠΎΠΆΠ΅ΡΠ΅ ΡΠ·Π΅ΡΠΈ ΠΊΠΎΠ΄
Π‘Π°Π΄Π° ΡΠ΅ Π½Π°ΡΠ° Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠ° ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°Π½Π° ΠΈ ΡΠ°Π΄ΠΈ. ΠΠΎΠΆΠ΅ΡΠ΅ ΠΏΠΎΠΊΡΠ΅Π½ΡΡΠΈ Π°Π»Π°ΡΠΊΠ΅ Π·Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ΅ΡΠ΅ Π·Π° ΡΠ°Π·Π»ΠΈΡΠΈΡΠ΅ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ΅ Π½Π° ΡΠ»Π΅Π΄Π΅ΡΠΈ Π½Π°ΡΠΈΠ½:
ΠΏΠΎΠΏΡΠΏ ->
ΠΡΠΈΡΡΡΠΏ ΠΊΠΎΠ½Π·ΠΎΠ»ΠΈ ΡΠΊΡΠΈΠΏΡΠ΅ ΡΠ°Π΄ΡΠΆΠ°ΡΠ° Π²ΡΡΠΈ ΡΠ΅ ΠΏΡΠ΅ΠΊΠΎ ΠΊΠΎΠ½Π·ΠΎΠ»Π΅ ΡΠ°ΠΌΠ΅ ΡΡΡΠ°Π½ΠΈΡΠ΅ Π½Π° ΠΊΠΎΡΠΎΡ ΡΠ΅ ΠΏΠΎΠΊΡΠ΅Π½ΡΡΠ°.
Π Π°Π·ΠΌΠ΅Π½Π° ΠΏΠΎΡΡΠΊΠ°
ΠΠ°ΠΊΠ»Π΅, ΠΌΠΎΡΠ°ΠΌΠΎ ΡΡΠΏΠΎΡΡΠ°Π²ΠΈΡΠΈ Π΄Π²Π° ΠΊΠ°Π½Π°Π»Π° ΠΊΠΎΠΌΡΠ½ΠΈΠΊΠ°ΡΠΈΡΠ΅: ΠΏΠΎΠ·Π°Π΄ΠΈΠ½Ρ ΠΈΠ½ΠΏΠ°Π³Π΅ <-> ΠΈ ΠΏΠΎΠ·Π°Π΄ΠΈΠ½Ρ ΠΈΡΠΊΠ°ΡΡΡΠ΅Π³ ΠΏΡΠΎΠ·ΠΎΡΠ°. ΠΠΎΠΆΠ΅ΡΠ΅, Π½Π°ΡΠ°Π²Π½ΠΎ, ΡΠ°ΠΌΠΎ ΡΠ»Π°ΡΠΈ ΠΏΠΎΡΡΠΊΠ΅ Π½Π° ΠΏΠΎΡΡ ΠΈ ΠΈΠ·ΠΌΠΈΡΠ»ΠΈΡΠΈ ΡΠΎΠΏΡΡΠ²Π΅Π½ΠΈ ΠΏΡΠΎΡΠΎΠΊΠΎΠ», Π°Π»ΠΈ ΡΠ° Π²ΠΈΡΠ΅ Π²ΠΎΠ»ΠΈΠΌ ΠΏΡΠΈΡΡΡΠΏ ΠΊΠΎΡΠΈ ΡΠ°ΠΌ Π²ΠΈΠ΄Π΅ΠΎ Ρ ΠΌΠ΅ΡΠ°ΠΌΠ°ΡΠΊ ΠΏΡΠΎΡΠ΅ΠΊΡΡ ΠΎΡΠ²ΠΎΡΠ΅Π½ΠΎΠ³ ΠΊΠΎΠ΄Π°.
ΠΠ²ΠΎ ΡΠ΅ ΠΏΡΠΎΡΠΈΡΠ΅ΡΠ΅ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠ° Π·Π° ΡΠ°Π΄ ΡΠ° ΠΡΡ Π΅ΡΠ΅ΡΠΌ ΠΌΡΠ΅ΠΆΠΎΠΌ. Π£ ΡΠ΅ΠΌΡ ΡΠ°Π·Π»ΠΈΡΠΈΡΠΈ Π΄Π΅Π»ΠΎΠ²ΠΈ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ΅ ΠΊΠΎΠΌΡΠ½ΠΈΡΠΈΡΠ°ΡΡ ΠΏΡΠ΅ΠΊΠΎ Π ΠΠ¦-Π° ΠΊΠΎΡΠΈΡΡΠ΅ΡΠΈ Π΄Π½ΠΎΠ΄Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΡ. ΠΠΌΠΎΠ³ΡΡΠ°Π²Π° Π²Π°ΠΌ Π΄Π° ΠΎΡΠ³Π°Π½ΠΈΠ·ΡΡΠ΅ΡΠ΅ ΡΠ°Π·ΠΌΠ΅Π½Ρ ΠΏΡΠΈΠ»ΠΈΡΠ½ΠΎ Π±ΡΠ·ΠΎ ΠΈ Π·Π³ΠΎΠ΄Π½ΠΎ Π°ΠΊΠΎ ΡΠΎΡ ΠΎΠ±Π΅Π·Π±Π΅Π΄ΠΈΡΠ΅ Π½ΠΎΠ΄Π΅ΡΡ ΡΡΡΠ΅Π°ΠΌ ΠΊΠ°ΠΎ ΡΡΠ°Π½ΡΠΏΠΎΡΡ (ΡΡΠΎ Π·Π½Π°ΡΠΈ ΠΎΠ±ΡΠ΅ΠΊΠ°Ρ ΠΊΠΎΡΠΈ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠΈΡΠ° ΠΈΡΡΠΈ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΡΡ):
import Dnode from "dnode/browser";
// Π ΡΡΠΎΠΌ ΠΏΡΠΈΠΌΠ΅ΡΠ΅ ΡΡΠ»ΠΎΠ²ΠΈΠΌΡΡ ΡΡΠΎ ΠΊΠ»ΠΈΠ΅Π½Ρ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎ Π²ΡΠ·ΡΠ²Π°Π΅Ρ ΡΡΠ½ΠΊΡΠΈΠΈ Π½Π° ΡΠ΅ΡΠ²Π΅ΡΠ΅, Ρ
ΠΎΡΡ Π½ΠΈΡΠ΅Π³ΠΎ Π½Π°ΠΌ Π½Π΅ ΠΌΠ΅ΡΠ°Π΅Ρ ΡΠ΄Π΅Π»Π°ΡΡ ΡΡΠΎ Π΄Π²ΡΠ½Π°ΠΏΡΠ°Π²Π»Π΅Π½Π½ΡΠΌ
// CΠ΅ΡΠ²Π΅Ρ
// API, ΠΊΠΎΡΠΎΡΠΎΠ΅ ΠΌΡ Ρ
ΠΎΡΠΈΠΌ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²ΠΈΡΡ
const dnode = Dnode({
hello: (cb) => cb(null, "world")
})
// Π’ΡΠ°Π½ΡΠΏΠΎΡΡ, ΠΏΠΎΠ²Π΅ΡΡ
ΠΊΠΎΡΠΎΡΠΎΠ³ΠΎ Π±ΡΠ΄Π΅Ρ ΡΠ°Π±ΠΎΡΠ°ΡΡ dnode. ΠΡΠ±ΠΎΠΉ nodejs ΡΡΡΠΈΠΌ. Π Π±ΡΠ°ΡΠ·Π΅ΡΠ΅ Π΅ΡΡΡ Π±ΠΈΠ±ΠΈΠ»ΠΈΠΎΡΠ΅ΠΊΠ° 'readable-stream'
connectionStream.pipe(dnode).pipe(connectionStream)
// ΠΠ»ΠΈΠ΅Π½Ρ
const dnodeClient = Dnode() // ΠΡΠ·ΠΎΠ² Π±Π΅Π· Π°Π³ΡΡΠΌΠ΅Π½ΡΠ° Π·Π½Π°ΡΠΈΡ ΡΡΠΎ ΠΌΡ Π½Π΅ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅ΠΌ API Π½Π° Π΄ΡΡΠ³ΠΎΠΉ ΡΡΠΎΡΠΎΠ½Π΅
// ΠΡΠ²Π΅Π΄Π΅Ρ Π² ΠΊΠΎΠ½ΡΠΎΠ»Ρ world
dnodeClient.once('remote', remote => {
remote.hello(((err, value) => console.log(value)))
})
Π‘Π°Π΄Π° ΡΠ΅ΠΌΠΎ ΠΊΡΠ΅ΠΈΡΠ°ΡΠΈ ΠΊΠ»Π°ΡΡ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ΅. ΠΠ½ ΡΠ΅ ΠΊΡΠ΅ΠΈΡΠ°ΡΠΈ ΠΠΠ ΠΎΠ±ΡΠ΅ΠΊΡΠ΅ Π·Π° ΠΈΡΠΊΠ°ΡΡΡΡ ΠΈ Π²Π΅Π± ΡΡΡΠ°Π½ΠΈΡΡ ΠΈ ΠΊΡΠ΅ΠΈΡΠ°ΡΠΈ Π΄Π½ΠΎΠ΄Π΅ Π·Π° ΡΠΈΡ :
import Dnode from 'dnode/browser';
export class SignerApp {
// ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ ΠΎΠ±ΡΠ΅ΠΊΡ API Π΄Π»Ρ ui
popupApi(){
return {
hello: cb => cb(null, 'world')
}
}
// ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ ΠΎΠ±ΡΠ΅Ρ API Π΄Π»Ρ ΡΡΡΠ°Π½ΠΈΡΡ
pageApi(){
return {
hello: cb => cb(null, 'world')
}
}
// ΠΠΎΠ΄ΠΊΠ»ΡΡΠ°Π΅Ρ popup ui
connectPopup(connectionStream){
const api = this.popupApi();
const dnode = Dnode(api);
connectionStream.pipe(dnode).pipe(connectionStream);
dnode.on('remote', (remote) => {
console.log(remote)
})
}
// ΠΠΎΠ΄ΠΊΠ»ΡΡΠ°Π΅Ρ ΡΡΡΠ°Π½ΠΈΡΡ
connectPage(connectionStream, origin){
const api = this.popupApi();
const dnode = Dnode(api);
connectionStream.pipe(dnode).pipe(connectionStream);
dnode.on('remote', (remote) => {
console.log(origin);
console.log(remote)
})
}
}
ΠΠ²Π΄Π΅ ΠΈ ΠΈΡΠΏΠΎΠ΄, ΡΠΌΠ΅ΡΡΠΎ Π³Π»ΠΎΠ±Π°Π»Π½ΠΎΠ³ Π¦Ρ ΡΠΎΠΌΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΠ°, ΠΊΠΎΡΠΈΡΡΠΈΠΌΠΎ Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΡ ΠΠΏΠΈ, ΠΊΠΎΡΠ° ΠΏΡΠΈΡΡΡΠΏΠ° Π¦Ρ ΡΠΎΠΌΠ΅-Ρ Ρ ΠΠΎΠΎΠ³Π»Π΅-ΠΎΠ²ΠΎΠΌ ΠΏΡΠ΅Π³Π»Π΅Π΄Π°ΡΡ ΠΈ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΡ Ρ Π΄ΡΡΠ³ΠΈΠΌ. ΠΠ²ΠΎ ΡΠ΅ ΡΡΠ°ΡΠ΅Π½ΠΎ ΡΠ°Π΄ΠΈ ΠΊΠΎΠΌΠΏΠ°ΡΠΈΠ±ΠΈΠ»Π½ΠΎΡΡΠΈ ΡΠ° ΡΠ°Π·Π»ΠΈΡΠΈΡΠΈΠΌ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΠΈΠΌΠ°, Π°Π»ΠΈ Π·Π° ΠΏΠΎΡΡΠ΅Π±Π΅ ΠΎΠ²ΠΎΠ³ ΡΠ»Π°Π½ΠΊΠ° ΠΌΠΎΠΆΠ΅ ΡΠ΅ ΡΠ΅Π΄Π½ΠΎΡΡΠ°Π²Π½ΠΎ ΠΊΠΎΡΠΈΡΡΠΈΡΠΈ 'ΡΡ ΡΠΎΠΌΠ΅.ΡΡΠ½ΡΠΈΠΌΠ΅.ΡΠΎΠ½Π½Π΅ΡΡ'.
Π₯Π°ΡΠ΄Π΅ Π΄Π° Π½Π°ΠΏΡΠ°Π²ΠΈΠΌΠΎ ΠΈΠ½ΡΡΠ°Π½ΡΡ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ΅ Ρ ΡΠΊΡΠΈΠΏΡΠΈ Ρ ΠΏΠΎΠ·Π°Π΄ΠΈΠ½ΠΈ:
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";
const app = new SignerApp();
// onConnect ΡΡΠ°Π±Π°ΡΡΠ²Π°Π΅Ρ ΠΏΡΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠΈ 'ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ²' (contentscript, popup, ΠΈΠ»ΠΈ ΡΡΡΠ°Π½ΠΈΡΠ° ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ)
extensionApi.runtime.onConnect.addListener(connectRemote);
function connectRemote(remotePort) {
const processName = remotePort.name;
const portStream = new PortStream(remotePort);
// ΠΡΠΈ ΡΡΡΠ°Π½ΠΎΠ²ΠΊΠ΅ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ ΠΌΠΎΠΆΠ½ΠΎ ΡΠΊΠ°Π·ΡΠ²Π°ΡΡ ΠΈΠΌΡ, ΠΏΠΎ ΡΡΠΎΠΌΡ ΠΈΠΌΠ΅Π½ΠΈ ΠΌΡ ΠΈ ΠΎΠΏΠΏΡΠ΅Π΄Π΅Π»ΡΠ΅ΠΌ ΠΊΡΠΎ ΠΊ Π½Π°ΠΌ ΠΏΠΎΠ΄Π»ΡΡΠΈΠ»ΡΡ, ΠΊΠΎΠ½ΡΠ΅Π½ΡΡΠΊΡΠΈΠΏΡ ΠΈΠ»ΠΈ ui
if (processName === 'contentscript'){
const origin = remotePort.sender.url
app.connectPage(portStream, origin)
}else{
app.connectPopup(portStream)
}
}
ΠΠΎΡΡΠΎ Π΄Π½ΠΎΠ΄Π΅ ΡΠ°Π΄ΠΈ ΡΠ° ΡΡΡΠ΅Π°ΠΌΠΎΠ²ΠΈΠΌΠ°, Π° ΠΌΠΈ Π΄ΠΎΠ±ΠΈΡΠ°ΠΌΠΎ ΠΏΠΎΡΡ, ΠΏΠΎΡΡΠ΅Π±Π½Π° ΡΠ΅ ΠΊΠ»Π°ΡΠ° Π°Π΄Π°ΠΏΡΠ΅ΡΠ°. ΠΠ°ΠΏΡΠ°Π²ΡΠ΅Π½ ΡΠ΅ ΠΏΠΎΠΌΠΎΡΡ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ΅ ΡΠ΅Π°Π΄Π°Π±Π»Π΅-ΡΡΡΠ΅Π°ΠΌ, ΠΊΠΎΡΠ° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠΈΡΠ° Π½ΠΎΠ΄Π΅ΡΡ ΡΡΡΠ΅Π°ΠΌΠΎΠ²Π΅ Ρ ΠΏΡΠ΅ΡΡΠ°ΠΆΠΈΠ²Π°ΡΡ:
import {Duplex} from 'readable-stream';
export class PortStream extends Duplex{
constructor(port){
super({objectMode: true});
this._port = port;
port.onMessage.addListener(this._onMessage.bind(this));
port.onDisconnect.addListener(this._onDisconnect.bind(this))
}
_onMessage(msg) {
if (Buffer.isBuffer(msg)) {
delete msg._isBuffer;
const data = new Buffer(msg);
this.push(data)
} else {
this.push(msg)
}
}
_onDisconnect() {
this.destroy()
}
_read(){}
_write(msg, encoding, cb) {
try {
if (Buffer.isBuffer(msg)) {
const data = msg.toJSON();
data._isBuffer = true;
this._port.postMessage(data)
} else {
this._port.postMessage(msg)
}
} catch (err) {
return cb(new Error('PortStream - disconnected'))
}
cb()
}
}
Π‘Π°Π΄Π° Π½Π°ΠΏΡΠ°Π²ΠΈΠΌΠΎ Π²Π΅Π·Ρ Ρ ΠΊΠΎΡΠΈΡΠ½ΠΈΡΠΊΠΎΠΌ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΡΡΡ:
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import Dnode from 'dnode/browser';
const DEV_MODE = process.env.NODE_ENV !== 'production';
setupUi().catch(console.error);
async function setupUi(){
// Π’Π°ΠΊΠΆΠ΅, ΠΊΠ°ΠΊ ΠΈ Π² ΠΊΠ»Π°ΡΡΠ΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ ΡΠΎΠ·Π΄Π°Π΅ΠΌ ΠΏΠΎΡΡ, ΠΎΠ±ΠΎΡΠ°ΡΠΈΠ²Π°Π΅ΠΌ Π² stream, Π΄Π΅Π»Π°Π΅ΠΌ dnode
const backgroundPort = extensionApi.runtime.connect({name: 'popup'});
const connectionStream = new PortStream(backgroundPort);
const dnode = Dnode();
connectionStream.pipe(dnode).pipe(connectionStream);
const background = await new Promise(resolve => {
dnode.once('remote', api => {
resolve(api)
})
});
// ΠΠ΅Π»Π°Π΅ΠΌ ΠΎΠ±ΡΠ΅ΠΊΡ API Π΄ΠΎΡΡΡΠΏΠ½ΡΠΌ ΠΈΠ· ΠΊΠΎΠ½ΡΠΎΠ»ΠΈ
if (DEV_MODE){
global.background = background;
}
}
ΠΠ°ΡΠΈΠΌ ΠΊΡΠ΅ΠΈΡΠ°ΠΌΠΎ Π²Π΅Π·Ρ Ρ ΡΠΊΡΠΈΠΏΡΠΈ ΡΠ°Π΄ΡΠΆΠ°ΡΠ°:
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import PostMessageStream from 'post-message-stream';
setupConnection();
injectScript();
function setupConnection(){
const backgroundPort = extensionApi.runtime.connect({name: 'contentscript'});
const backgroundStream = new PortStream(backgroundPort);
const pageStream = new PostMessageStream({
name: 'content',
target: 'page',
});
pageStream.pipe(backgroundStream).pipe(pageStream);
}
function injectScript(){
try {
// inject in-page script
let script = document.createElement('script');
script.src = extensionApi.extension.getURL('inpage.js');
const container = document.head || document.documentElement;
container.insertBefore(script, container.children[0]);
script.onload = () => script.remove();
} catch (e) {
console.error('Injection failed.', e);
}
}
ΠΠΎΡΡΠΎ Π½Π°ΠΌ ΠΠΠ Π½ΠΈΡΠ΅ ΠΏΠΎΡΡΠ΅Π±Π°Π½ Ρ ΡΠΊΡΠΈΠΏΡΠΈ ΡΠ°Π΄ΡΠΆΠ°ΡΠ°, Π²Π΅Ρ Π΄ΠΈΡΠ΅ΠΊΡΠ½ΠΎ Π½Π° ΡΡΡΠ°Π½ΠΈΡΠΈ, ΡΠ°Π΄ΠΈΠΌΠΎ Π΄Π²Π΅ ΡΡΠ²Π°ΡΠΈ:
- ΠΡΠ°Π²ΠΈΠΌΠΎ Π΄Π²Π° ΡΠΎΠΊΠ°. ΠΠ΅Π΄Π°Π½ - ΠΏΡΠ΅ΠΌΠ° ΡΡΡΠ°Π½ΠΈΡΠΈ, Π½Π° Π²ΡΡ
Ρ ΠΏΠΎΡΡΠΊΠ΅. ΠΠ° ΠΎΠ²ΠΎ ΠΊΠΎΡΠΈΡΡΠΈΠΌΠΎ ΠΎΠ²ΠΎ
ΠΎΠ²Π°Ρ ΠΏΠ°ΠΊΠ΅Ρ ΠΎΠ΄ ΠΊΡΠ΅Π°ΡΠΎΡΠ° ΠΌΠ΅ΡΠ°ΠΌΠ°ΡΠΊΠ΅. ΠΡΡΠ³ΠΈ ΡΠΎΠΊ ΡΠ΅ Ρ ΠΏΠΎΠ·Π°Π΄ΠΈΠ½ΠΈ ΠΏΡΠ΅ΠΊΠΎ ΠΏΡΠΈΠΌΡΠ΅Π½ΠΎΠ³ ΠΏΠΎΡΡΠ°runtime.connect
. Π₯Π°ΡΠ΄Π΅ Π΄Π° ΠΈΡ ΠΊΡΠΏΠΈΠΌΠΎ. Π‘Π°Π΄Π° ΡΠ΅ ΡΡΡΠ°Π½ΠΈΡΠ° ΠΈΠΌΠ°ΡΠΈ ΡΠΎΠΊ Ρ ΠΏΠΎΠ·Π°Π΄ΠΈΠ½ΠΈ. - Π£Π±Π°ΡΠΈΡΠ΅ ΡΠΊΡΠΈΠΏΡΡ Ρ ΠΠΠ. ΠΡΠ΅ΡΠ·ΠΌΠΈΡΠ΅ ΡΠΊΡΠΈΠΏΡΡ (ΠΏΡΠΈΡΡΡΠΏ ΡΠΎΡ ΡΠ΅ Π±ΠΈΠΎ Π΄ΠΎΠ·Π²ΠΎΡΠ΅Π½ Ρ ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΡ) ΠΈ ΠΊΡΠ΅ΠΈΡΠ°ΡΡΠ΅ ΠΎΠ·Π½Π°ΠΊΡ
script
ΡΠ° ΡΠ°Π΄ΡΠΆΠ°ΡΠ΅ΠΌ ΡΠ½ΡΡΡΠ°:
import PostMessageStream from 'post-message-stream';
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
setupConnection();
injectScript();
function setupConnection(){
// Π‘ΡΡΠΈΠΌ ΠΊ Π±Π΅ΠΊΠ³ΡΠ°ΡΠ½Π΄Ρ
const backgroundPort = extensionApi.runtime.connect({name: 'contentscript'});
const backgroundStream = new PortStream(backgroundPort);
// Π‘ΡΡΠΈΠΌ ΠΊ ΡΡΡΠ°Π½ΠΈΡΠ΅
const pageStream = new PostMessageStream({
name: 'content',
target: 'page',
});
pageStream.pipe(backgroundStream).pipe(pageStream);
}
function injectScript(){
try {
// inject in-page script
let script = document.createElement('script');
script.src = extensionApi.extension.getURL('inpage.js');
const container = document.head || document.documentElement;
container.insertBefore(script, container.children[0]);
script.onload = () => script.remove();
} catch (e) {
console.error('Injection failed.', e);
}
}
Π‘Π°Π΄Π° ΠΊΡΠ΅ΠΈΡΠ°ΠΌΠΎ Π°ΠΏΠΈ ΠΎΠ±ΡΠ΅ΠΊΠ°Ρ Ρ ΠΈΠ½ΠΏΠ°Π³Π΅ ΠΈ ΠΏΠΎΡΡΠ°Π²ΡΠ°ΠΌΠΎ Π³Π° Π½Π° Π³Π»ΠΎΠ±Π°Π»Π½ΠΎ:
import PostMessageStream from 'post-message-stream';
import Dnode from 'dnode/browser';
setupInpageApi().catch(console.error);
async function setupInpageApi() {
// Π‘ΡΡΠΈΠΌ ΠΊ ΠΊΠΎΠ½ΡΠ΅Π½ΡΡΠΊΡΠΈΠΏΡΡ
const connectionStream = new PostMessageStream({
name: 'page',
target: 'content',
});
const dnode = Dnode();
connectionStream.pipe(dnode).pipe(connectionStream);
// ΠΠΎΠ»ΡΡΠ°Π΅ΠΌ ΠΎΠ±ΡΠ΅ΠΊΡ API
const pageApi = await new Promise(resolve => {
dnode.once('remote', api => {
resolve(api)
})
});
// ΠΠΎΡΡΡΠΏ ΡΠ΅ΡΠ΅Π· window
global.SignerApp = pageApi;
}
ΠΠΈ ΡΠΌΠΎ ΡΠΏΡΠ΅ΠΌΠ½ΠΈ
ΠΡΠ°Π·Π°Π½ ΠΠΠ ΠΈ ΠΏΠΎΡΠ΅ΠΊΠ»ΠΎ. ΠΠ° ΡΡΡΠ°Π½ΠΈ ΡΡΡΠ°Π½ΠΈΡΠ΅, ΡΡΠ½ΠΊΡΠΈΡΡ Ρ Π΅Π»Π»ΠΎ ΠΌΠΎΠΆΠ΅ΠΌΠΎ ΠΏΠΎΠ·Π²Π°ΡΠΈ ΠΎΠ²Π°ΠΊΠΎ:
Π Π°Π΄ ΡΠ° ΡΡΠ½ΠΊΡΠΈΡΠ°ΠΌΠ° ΠΏΠΎΠ²ΡΠ°ΡΠ½ΠΎΠ³ ΠΏΠΎΠ·ΠΈΠ²Π° Ρ ΠΌΠΎΠ΄Π΅ΡΠ½ΠΎΠΌ ΠΠ‘-Ρ ΡΠ΅ Π»ΠΎΡ ΠΌΠ°Π½ΠΈΡΠΈ, ΠΏΠ° Ρ Π°ΡΠ΄Π΅ Π΄Π° Π½Π°ΠΏΠΈΡΠ΅ΠΌΠΎ ΠΌΠ°Π»ΠΈ ΠΏΠΎΠΌΠΎΡΠ½ΠΈΠΊ Π·Π° ΠΊΡΠ΅ΠΈΡΠ°ΡΠ΅ Π΄Π½ΠΎΠ΄Π΅ ΠΊΠΎΡΠΈ Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡΡΠ°Π²Π° Π΄Π° ΠΏΡΠΎΡΠ»Π΅Π΄ΠΈΡΠ΅ ΠΠΠ ΠΎΠ±ΡΠ΅ΠΊΠ°Ρ ΡΡΠΈΠ»ΠΈΠΌΠ°.
ΠΠΠ ΠΎΠ±ΡΠ΅ΠΊΡΠΈ ΡΠ΅ ΡΠ°Π΄Π° ΠΈΠ·Π³Π»Π΅Π΄Π°ΡΠΈ ΠΎΠ²Π°ΠΊΠΎ:
export class SignerApp {
popupApi() {
return {
hello: async () => "world"
}
}
...
}
ΠΠΎΠ±ΠΈΡΠ°ΡΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΠ° ΡΠ° Π΄Π°ΡΠΈΠ½Π΅ ΠΎΠ²Π°ΠΊΠΎ:
import {cbToPromise, transformMethods} from "../../src/utils/setupDnode";
const pageApi = await new Promise(resolve => {
dnode.once('remote', remoteApi => {
// Π‘ ΠΏΠΎΠΌΠΎΡΡΡ ΡΡΠΈΠ»ΠΈΡ ΠΌΠ΅Π½ΡΠ΅ΠΌ Π²ΡΠ΅ callback Π½Π° promise
resolve(transformMethods(cbToPromise, remoteApi))
})
});
Π ΠΏΠΎΠ·ΠΈΠ²Π°ΡΠ΅ ΡΡΠ½ΠΊΡΠΈΡΠ° Π²ΡΠ°ΡΠ° ΠΎΠ±Π΅ΡΠ°ΡΠ΅:
ΠΠΎΡΡΡΠΏΠ½Π° Π²Π΅ΡΠ·ΠΈΡΠ° ΡΠ° Π°ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠΌ ΡΡΠ½ΠΊΡΠΈΡΠ°ΠΌΠ°
Π‘Π²Π΅ Ρ ΡΠ²Π΅ΠΌΡ, ΠΏΡΠΈΡΡΡΠΏ Π ΠΠ¦-Π° ΠΈ ΡΡΡΠΈΠΌΠ° ΠΈΠ·Π³Π»Π΅Π΄Π° ΠΏΡΠΈΠ»ΠΈΡΠ½ΠΎ ΡΠ»Π΅ΠΊΡΠΈΠ±ΠΈΠ»Π°Π½: ΠΌΠΎΠΆΠ΅ΠΌΠΎ ΠΊΠΎΡΠΈΡΡΠΈΡΠΈ ΠΏΠ°ΡΠ½ΠΎ ΠΌΡΠ»ΡΠΈΠΏΠ»Π΅ΠΊΡΠΈΡΠ°ΡΠ΅ ΠΈ ΠΊΡΠ΅ΠΈΡΠ°ΡΠΈ Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ ΡΠ°Π·Π»ΠΈΡΠΈΡΠΈΡ ΠΠΠ-ΡΠ° Π·Π° ΡΠ°Π·Π»ΠΈΡΠΈΡΠ΅ Π·Π°Π΄Π°ΡΠΊΠ΅. Π£ ΠΏΡΠΈΠ½ΡΠΈΠΏΡ, Π΄Π½ΠΎΠ΄Π΅ ΡΠ΅ ΠΌΠΎΠΆΠ΅ ΠΊΠΎΡΠΈΡΡΠΈΡΠΈ Π±ΠΈΠ»ΠΎ Π³Π΄Π΅, Π³Π»Π°Π²Π½Π° ΡΡΠ²Π°Ρ ΡΠ΅ Π΄Π° ΡΠ΅ ΡΡΠ°Π½ΡΠΏΠΎΡΡ ΠΎΠΌΠΎΡΠ° Ρ ΠΎΠ±Π»ΠΈΠΊΡ Π½ΠΎΠ΄Π΅ΡΡ ΡΠΎΠΊΠ°.
ΠΠ»ΡΠ΅ΡΠ½Π°ΡΠΈΠ²Π° ΡΠ΅ ΠΠ‘ΠΠ ΡΠΎΡΠΌΠ°Ρ, ΠΊΠΎΡΠΈ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠΈΡΠ° ΠΏΡΠΎΡΠΎΠΊΠΎΠ» ΠΠ‘ΠΠ Π ΠΠ¦ 2. ΠΠ΅ΡΡΡΠΈΠΌ, ΡΠ°Π΄ΠΈ ΡΠ° ΡΠΏΠ΅ΡΠΈΡΠΈΡΠ½ΠΈΠΌ ΡΡΠ°Π½ΡΠΏΠΎΡΡΠΈΠΌΠ° (Π’Π¦Π ΠΈ Π₯Π’Π’Π(Π‘)), ΡΡΠΎ Ρ Π½Π°ΡΠ΅ΠΌ ΡΠ»ΡΡΠ°ΡΡ Π½ΠΈΡΠ΅ ΠΏΡΠΈΠΌΠ΅Π½ΡΠΈΠ²ΠΎ.
ΠΠ½ΡΠ΅ΡΠ½ΠΎ ΡΡΠ°ΡΠ΅ ΠΈ Π»ΠΎΠΊΠ°Π»Π½ΠΎ ΡΠΊΠ»Π°Π΄ΠΈΡΡΠ΅
ΠΠΎΡΠ°ΡΠ΅ΠΌΠΎ Π΄Π° ΡΠ°ΡΡΠ²Π°ΠΌΠΎ ΠΈΠ½ΡΠ΅ΡΠ½ΠΎ ΡΡΠ°ΡΠ΅ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ΅ - Π±Π°ΡΠ΅ΠΌ ΠΊΡΡΡΠ΅Π²Π΅ Π·Π° ΠΏΠΎΡΠΏΠΈΡΠΈΠ²Π°ΡΠ΅. ΠΠΎΠΆΠ΅ΠΌΠΎ ΠΏΡΠΈΠ»ΠΈΡΠ½ΠΎ Π»Π°ΠΊΠΎ Π΄ΠΎΠ΄Π°ΡΠΈ ΡΡΠ°ΡΠ΅ Ρ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΡ ΠΈ ΠΌΠ΅ΡΠΎΠ΄Π΅ Π·Π° ΡΠ΅Π³ΠΎΠ²Ρ ΠΏΡΠΎΠΌΠ΅Π½Ρ Ρ ΠΈΡΠΊΠ°ΡΡΡΠ΅ΠΌ ΠΠΠ-ΡΡ:
import {setupDnode} from "./utils/setupDnode";
export class SignerApp {
constructor(){
this.store = {
keys: [],
};
}
addKey(key){
this.store.keys.push(key)
}
removeKey(index){
this.store.keys.splice(index,1)
}
popupApi(){
return {
addKey: async (key) => this.addKey(key),
removeKey: async (index) => this.removeKey(index)
}
}
...
}
Π£ ΠΏΠΎΠ·Π°Π΄ΠΈΠ½ΠΈ, ΡΠ²Π΅ ΡΠ΅ΠΌΠΎ ΡΠΌΠΎΡΠ°ΡΠΈ Ρ ΡΡΠ½ΠΊΡΠΈΡΡ ΠΈ Π½Π°ΠΏΠΈΡΠ°ΡΠΈ ΠΎΠ±ΡΠ΅ΠΊΠ°Ρ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ΅ Ρ ΠΏΡΠΎΠ·ΠΎΡ ΡΠ°ΠΊΠΎ Π΄Π° ΠΌΠΎΠΆΠ΅ΠΌΠΎ Π΄Π° ΡΠ°Π΄ΠΈΠΌΠΎ ΡΠ° ΡΠΈΠΌ ΡΠ° ΠΊΠΎΠ½Π·ΠΎΠ»Π΅:
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";
const DEV_MODE = process.env.NODE_ENV !== 'production';
setupApp();
function setupApp() {
const app = new SignerApp();
if (DEV_MODE) {
global.app = app;
}
extensionApi.runtime.onConnect.addListener(connectRemote);
function connectRemote(remotePort) {
const processName = remotePort.name;
const portStream = new PortStream(remotePort);
if (processName === 'contentscript') {
const origin = remotePort.sender.url;
app.connectPage(portStream, origin)
} else {
app.connectPopup(portStream)
}
}
}
Π₯Π°ΡΠ΄Π΅ Π΄Π° Π΄ΠΎΠ΄Π°ΠΌΠΎ Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ ΠΊΡΡΡΠ΅Π²Π° ΡΠ° Π£Π ΠΊΠΎΠ½Π·ΠΎΠ»Π΅ ΠΈ Π²ΠΈΠ΄ΠΈΠΌΠΎ ΡΡΠ° ΡΠ΅ Π΄Π΅ΡΠ°Π²Π° ΡΠ° ΡΡΠ°ΡΠ΅ΠΌ:
Π‘ΡΠ°ΡΠ΅ ΡΡΠ΅Π±Π° ΡΡΠΈΠ½ΠΈΡΠΈ ΠΏΠΎΡΡΠΎΡΠ°Π½ΠΈΠΌ ΠΊΠ°ΠΊΠΎ ΡΠ΅ ΠΊΡΡΡΠ΅Π²ΠΈ Π½Π΅ Π±ΠΈ ΠΈΠ·Π³ΡΠ±ΠΈΠ»ΠΈ ΠΏΡΠΈΠ»ΠΈΠΊΠΎΠΌ ΠΏΠΎΠ½ΠΎΠ²Π½ΠΎΠ³ ΠΏΠΎΠΊΡΠ΅ΡΠ°ΡΠ°.
Π‘Π°ΡΡΠ²Π°ΡΠ΅ΠΌΠΎ Π³Π° Ρ Π»ΠΎΡΠ°Π»Π‘ΡΠΎΡΠ°Π³Π΅, Π·Π°ΠΌΠ΅ΡΡΡΡΡΠΈ Π³Π° ΡΠ° ΡΠ²Π°ΠΊΠΎΠΌ ΠΏΡΠΎΠΌΠ΅Π½ΠΎΠΌ. ΠΠ°ΠΊΠΎΠ½ ΡΠΎΠ³Π°, ΠΏΡΠΈΡΡΡΠΏ ΡΠ΅ ΠΌΡ ΡΠ°ΠΊΠΎΡΠ΅ Π±ΠΈΡΠΈ Π½Π΅ΠΎΠΏΡ ΠΎΠ΄Π°Π½ Π·Π° ΠΊΠΎΡΠΈΡΠ½ΠΈΡΠΊΠΈ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΡΡ, Π° ΡΠ°ΠΊΠΎΡΠ΅ Π±ΠΈΡ ΠΆΠ΅Π»Π΅ΠΎ Π΄Π° ΡΠ΅ ΠΏΡΠ΅ΡΠΏΠ»Π°ΡΠΈΠΌ Π½Π° ΠΏΡΠΎΠΌΠ΅Π½Π΅. ΠΠ° ΠΎΡΠ½ΠΎΠ²Ρ ΠΎΠ²ΠΎΠ³Π°, Π±ΠΈΡΠ΅ Π·Π³ΠΎΠ΄Π½ΠΎ ΠΊΡΠ΅ΠΈΡΠ°ΡΠΈ Π²ΠΈΠ΄ΡΠΈΠ²ΠΎ ΡΠΊΠ»Π°Π΄ΠΈΡΡΠ΅ ΠΈ ΠΏΡΠ΅ΡΠΏΠ»Π°ΡΠΈΡΠΈ ΡΠ΅ Π½Π° ΡΠ΅Π³ΠΎΠ²Π΅ ΠΏΡΠΎΠΌΠ΅Π½Π΅.
ΠΠΎΡΠΈΡΡΠΈΡΠ΅ΠΌΠΎ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΡ ΠΌΠΎΠ±ΠΊ (
Π₯Π°ΡΠ΄Π΅ Π΄Π° Π΄ΠΎΠ΄Π°ΠΌΠΎ ΠΈΠ½ΠΈΡΠΈΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡΡ ΠΏΠΎΡΠ΅ΡΠ½ΠΎΠ³ ΡΡΠ°ΡΠ° ΠΈ ΡΡΠΈΠ½ΠΈΠΌΠΎ ΡΠΊΠ»Π°Π΄ΠΈΡΡΠ΅ Π²ΠΈΠ΄ΡΠΈΠ²ΠΈΠΌ:
import {observable, action} from 'mobx';
import {setupDnode} from "./utils/setupDnode";
export class SignerApp {
constructor(initState = {}) {
// ΠΠ½Π΅ΡΠ½Π΅ store ΡΠ°ΠΊ ΠΈ ΠΎΡΡΠ°Π½Π΅ΡΡΡ ΡΠ΅ΠΌ ΠΆΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠΌ, ΡΠΎΠ»ΡΠΊΠΎ ΡΠ΅ΠΏΠ΅ΡΡ Π²ΡΠ΅ Π΅Π³ΠΎ ΠΏΠΎΠ»Ρ ΡΡΠ°Π»ΠΈ proxy, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΎΡΡΠ»Π΅ΠΆΠΈΠ²Π°ΡΡ Π΄ΠΎΡΡΡΠΏ ΠΊ Π½ΠΈΠΌ
this.store = observable.object({
keys: initState.keys || [],
});
}
// ΠΠ΅ΡΠΎΠ΄Ρ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΌΠ΅Π½ΡΡΡ observable ΠΏΡΠΈΠ½ΡΡΠΎ ΠΎΠ±ΠΎΡΠ°ΡΠΈΠ²Π°ΡΡ Π΄Π΅ΠΊΠΎΡΠ°ΡΠΎΡΠΎΠΌ
@action
addKey(key) {
this.store.keys.push(key)
}
@action
removeKey(index) {
this.store.keys.splice(index, 1)
}
...
}
βΠΡΠΏΠΎΠ΄ Ρ Π°ΡΠ±Π΅β, ΠΌΠΎΠ±ΠΊ ΡΠ΅ Π·Π°ΠΌΠ΅Π½ΠΈΠΎ ΡΠ²Π° ΠΏΠΎΡΠ° ΠΏΡΠΎΠ΄Π°Π²Π½ΠΈΡΠ΅ ΠΏΡΠΎΠΊΡΠΈΡΠ΅ΠΌ ΠΈ ΠΏΡΠ΅ΡΡΠ΅ΡΠ΅ ΡΠ²Π΅ ΠΏΠΎΠ·ΠΈΠ²Π΅ ΠΊΠ° ΡΠΈΠΌΠ°. ΠΠΈΡΠ΅ ΠΌΠΎΠ³ΡΡΠ΅ ΠΏΡΠ΅ΡΠΏΠ»Π°ΡΠΈΡΠΈ ΡΠ΅ Π½Π° ΠΎΠ²Π΅ ΠΏΠΎΡΡΠΊΠ΅.
Π£ Π½Π°ΡΡΠ°Π²ΠΊΡ ΡΡ ΡΠ΅ΡΡΠΎ ΠΊΠΎΡΠΈΡΡΠΈΡΠΈ ΠΈΠ·ΡΠ°Π· βΠΏΡΠΈ ΠΏΡΠΎΠΌΠ΅Π½ΠΈβ, ΠΈΠ°ΠΊΠΎ ΡΠΎ Π½ΠΈΡΠ΅ ΡΠ°ΡΠ²ΠΈΠΌ ΡΠ°ΡΠ½ΠΎ. ΠΠΎΠ±ΠΊ ΠΏΡΠ°ΡΠΈ ΠΏΡΠΈΡΡΡΠΏ ΠΏΠΎΡΠΈΠΌΠ°. ΠΠΎΡΠΈΡΡΠ΅ ΡΠ΅ Π³Π΅ΡΡΠ΅ΡΠΈ ΠΈ ΡΠ΅ΡΡΠ΅ΡΠΈ ΠΏΡΠΎΠΊΠΈ ΠΎΠ±ΡΠ΅ΠΊΠ°ΡΠ° ΠΊΠΎΡΠ΅ ΠΊΡΠ΅ΠΈΡΠ° Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ°.
ΠΠΊΡΠΈΠΎΠ½ΠΈ Π΄Π΅ΠΊΠΎΡΠ°ΡΠ΅ΡΠΈ ΠΈΠΌΠ°ΡΡ Π΄Π²Π΅ ΡΠ²ΡΡ Π΅:
- Π£ ΡΡΡΠΎΠ³ΠΎΠΌ ΡΠ΅ΠΆΠΈΠΌΡ ΡΠ° Π·Π°ΡΡΠ°Π²ΠΈΡΠΎΠΌ Π΅Π½ΡΠΎΡΡΠ΅ΠΡΡΠΈΠΎΠ½Ρ, ΠΌΠΎΠ±ΠΊ Π·Π°Π±ΡΠ°ΡΡΡΠ΅ Π΄ΠΈΡΠ΅ΠΊΡΠ½Ρ ΠΏΡΠΎΠΌΠ΅Π½Ρ ΡΡΠ°ΡΠ°. Π‘ΠΌΠ°ΡΡΠ° ΡΠ΅ Π΄Π° ΡΠ΅ Π΄ΠΎΠ±ΡΠ° ΠΏΡΠ°ΠΊΡΠ° ΡΠ°Π΄ΠΈΡΠΈ ΠΏΠΎΠ΄ ΡΡΡΠΎΠ³ΠΈΠΌ ΡΡΠ»ΠΎΠ²ΠΈΠΌΠ°.
- Π§Π°ΠΊ ΠΈ Π°ΠΊΠΎ ΡΡΠ½ΠΊΡΠΈΡΠ° ΠΏΡΠΎΠΌΠ΅Π½ΠΈ ΡΡΠ°ΡΠ΅ Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ ΠΏΡΡΠ° β Π½Π° ΠΏΡΠΈΠΌΠ΅Ρ, ΠΏΡΠΎΠΌΠ΅Π½ΠΈΠΌΠΎ Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ ΠΏΠΎΡΠ° Ρ Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ ΡΠ΅Π΄ΠΎΠ²Π° ΠΊΠΎΠ΄Π° β ΠΏΠΎΡΠΌΠ°ΡΡΠ°ΡΠΈ Π΄ΠΎΠ±ΠΈΡΠ°ΡΡ ΠΎΠ±Π°Π²Π΅ΡΡΠ΅ΡΠ΅ ΡΠ΅ΠΊ ΠΊΠ°Π΄Π° ΡΠ΅ Π·Π°Π²ΡΡΠΈ. ΠΠ²ΠΎ ΡΠ΅ ΠΏΠΎΡΠ΅Π±Π½ΠΎ Π²Π°ΠΆΠ½ΠΎ Π·Π° ΡΡΠΎΠ½ΡΠ΅Π½Π΄, Π³Π΄Π΅ Π½Π΅ΠΏΠΎΡΡΠ΅Π±Π½Π° Π°ΠΆΡΡΠΈΡΠ°ΡΠ° ΡΡΠ°ΡΠ° Π΄ΠΎΠ²ΠΎΠ΄Π΅ Π΄ΠΎ Π½Π΅ΠΏΠΎΡΡΠ΅Π±Π½ΠΎΠ³ ΠΏΡΠΈΠΊΠ°Π·ΠΈΠ²Π°ΡΠ° Π΅Π»Π΅ΠΌΠ΅Π½Π°ΡΠ°. Π£ Π½Π°ΡΠ΅ΠΌ ΡΠ»ΡΡΠ°ΡΡ, Π½ΠΈ ΠΏΡΠ²ΠΎ Π½ΠΈ Π΄ΡΡΠ³ΠΎ Π½ΠΈΡΡ ΠΏΠΎΡΠ΅Π±Π½ΠΎ ΡΠ΅Π»Π΅Π²Π°Π½ΡΠ½ΠΈ, Π°Π»ΠΈ ΡΠ΅ΠΌΠΎ ΡΠ»Π΅Π΄ΠΈΡΠΈ Π½Π°ΡΠ±ΠΎΡΡ ΠΏΡΠ°ΠΊΡΡ. Π£ΠΎΠ±ΠΈΡΠ°ΡΠ΅Π½ΠΎ ΡΠ΅ Π΄Π° ΡΠ΅ ΡΠ²ΠΈΠΌ ΡΡΠ½ΠΊΡΠΈΡΠ°ΠΌΠ° ΠΊΠΎΡΠ΅ ΠΌΠ΅ΡΠ°ΡΡ ΡΡΠ°ΡΠ΅ ΠΏΠΎΡΠΌΠ°ΡΡΠ°Π½ΠΈΡ ΠΏΠΎΡΠ° Π΄ΠΎΠ΄Π°ΡΡ Π΄Π΅ΠΊΠΎΡΠ°ΡΠΎΡΠΈ.
Π£ ΠΏΠΎΠ·Π°Π΄ΠΈΠ½ΠΈ ΡΠ΅ΠΌΠΎ Π΄ΠΎΠ΄Π°ΡΠΈ ΠΈΠ½ΠΈΡΠΈΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡΡ ΠΈ ΡΡΠ²Π°ΡΠ΅ ΡΡΠ°ΡΠ° Ρ Π»ΠΎΡΠ°Π»Π‘ΡΠΎΡΠ°Π³Π΅:
import {reaction, toJS} from 'mobx';
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";
// ΠΡΠΏΠΎΠΌΠΎΠ³Π°ΡΠ΅Π»ΡΠ½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ. ΠΠ°ΠΏΠΈΡΡΠ²Π°ΡΡ/ΡΠΈΡΠ°ΡΡ ΠΎΠ±ΡΠ΅ΠΊΡ Π²/ΠΈΠ· localStorage Π²ΠΈΠ΄Π΅ JSON ΡΡΡΠΎΠΊΠΈ ΠΏΠΎ ΠΊΠ»ΡΡΡ 'store'
import {loadState, saveState} from "./utils/localStorage";
const DEV_MODE = process.env.NODE_ENV !== 'production';
setupApp();
function setupApp() {
const initState = loadState();
const app = new SignerApp(initState);
if (DEV_MODE) {
global.app = app;
}
// Setup state persistence
// Π Π΅Π·ΡΠ»ΡΡΠ°Ρ reaction ΠΏΡΠΈΡΠ²Π°ΠΈΠ²Π°Π΅ΡΡΡ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΠΉ, ΡΡΠΎΠ±Ρ ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΡ ΠΌΠΎΠΆΠ½ΠΎ Π±ΡΠ»ΠΎ ΠΎΡΠΌΠ΅Π½ΠΈΡΡ. ΠΠ°ΠΌ ΡΡΠΎ Π½Π΅ Π½ΡΠΆΠ½ΠΎ, ΠΎΡΡΠ°Π²Π»Π΅Π½ΠΎ Π΄Π»Ρ ΠΏΡΠΈΠΌΠ΅ΡΠ°
const localStorageReaction = reaction(
() => toJS(app.store), // Π€ΡΠ½ΠΊΡΠΈΡ-ΡΠ΅Π»Π΅ΠΊΡΠΎΡ Π΄Π°Π½Π½ΡΡ
saveState // Π€ΡΠ½ΠΊΡΠΈΡ, ΠΊΠΎΡΠΎΡΠ°Ρ Π±ΡΠ΄Π΅Ρ Π²ΡΠ·Π²Π°Π½Π° ΠΏΡΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ Π΄Π°Π½Π½ΡΡ
, ΠΊΠΎΡΠΎΡΡΠ΅ Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ ΡΠ΅Π»Π΅ΠΊΡΠΎΡ
);
extensionApi.runtime.onConnect.addListener(connectRemote);
function connectRemote(remotePort) {
const processName = remotePort.name;
const portStream = new PortStream(remotePort);
if (processName === 'contentscript') {
const origin = remotePort.sender.url
app.connectPage(portStream, origin)
} else {
app.connectPopup(portStream)
}
}
}
ΠΠ²Π΄Π΅ ΡΠ΅ Π·Π°Π½ΠΈΠΌΡΠΈΠ²Π° ΡΡΠ½ΠΊΡΠΈΡΠ° ΡΠ΅Π°ΠΊΡΠΈΡΠ΅. ΠΠΌΠ° Π΄Π²Π° Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠ°:
- ΠΠΈΡΠ°Ρ ΠΏΠΎΠ΄Π°ΡΠ°ΠΊΠ°.
- Π ΡΠΊΠΎΠ²Π°Π»Π°Ρ ΠΊΠΎΡΠΈ ΡΠ΅ Π±ΠΈΡΠΈ ΠΏΠΎΠ·Π²Π°Π½ ΡΠ° ΠΎΠ²ΠΈΠΌ ΠΏΠΎΠ΄Π°ΡΠΈΠΌΠ° ΡΠ²Π°ΠΊΠΈ ΠΏΡΡ ΠΊΠ°Π΄Π° ΡΠ΅ ΠΏΡΠΎΠΌΠ΅Π½Π΅.
ΠΠ° ΡΠ°Π·Π»ΠΈΠΊΡ ΠΎΠ΄ ΡΠ΅Π΄ΡΠΊ-Π°, Π³Π΄Π΅ ΠΌΠΈ Π΅ΠΊΡΠΏΠ»ΠΈΡΠΈΡΠ½ΠΎ ΠΏΡΠΈΠΌΠ°ΠΌΠΎ ΡΡΠ°ΡΠ΅ ΠΊΠ°ΠΎ Π°ΡΠ³ΡΠΌΠ΅Π½Ρ, ΠΌΠΎΠ±ΠΊ ΠΏΠ°ΠΌΡΠΈ ΠΊΠΎΡΠΈΠΌ ΠΏΠΎΡΠΌΠ°ΡΡΠ°ΡΠΈΠΌΠ° ΠΏΡΠΈΡΡΡΠΏΠ°ΠΌΠΎ ΡΠ½ΡΡΠ°Ρ ΡΠ΅Π»Π΅ΠΊΡΠΎΡΠ° ΠΈ ΠΏΠΎΠ·ΠΈΠ²Π° ΡΡΠΊΠΎΠ²Π°Π»Π°Ρ ΡΠ°ΠΌΠΎ ΠΊΠ°Π΄Π° ΡΠ΅ ΠΏΡΠΎΠΌΠ΅Π½Π΅.
ΠΠ°ΠΆΠ½ΠΎ ΡΠ΅ ΡΠ°ΡΠ½ΠΎ ΡΠ°Π·ΡΠΌΠ΅ΡΠΈ ΠΊΠ°ΠΊΠΎ ΠΌΠΎΠ±ΠΊ ΠΎΠ΄Π»ΡΡΡΡΠ΅ Π½Π° ΠΊΠΎΡΠ΅ ΠΏΠΎΡΠΌΠ°ΡΡΠ°ΡΠ΅ ΡΠ΅ ΠΏΡΠ΅ΡΠΏΠ»Π°ΡΠΈΠΌΠΎ. ΠΠ° ΡΠ°ΠΌ Π½Π°ΠΏΠΈΡΠ°ΠΎ ΡΠ΅Π»Π΅ΠΊΡΠΎΡ Ρ ΠΎΠ²Π°ΠΊΠ²ΠΎΠΌ ΠΊΠΎΠ΄Ρ() => app.store
, ΡΠ°Π΄Π° ΡΠ΅Π°ΠΊΡΠΈΡΠ° Π½ΠΈΠΊΠ°Π΄Π° Π½Π΅ΡΠ΅ Π±ΠΈΡΠΈ ΠΏΠΎΠ·Π²Π°Π½Π°, ΠΏΠΎΡΡΠΎ ΡΠ°ΠΌΠΎ ΡΠΊΠ»Π°Π΄ΠΈΡΡΠ΅ Π½ΠΈΡΠ΅ Π²ΠΈΠ΄ΡΠΈΠ²ΠΎ, Π²Π΅Ρ ΡΠ°ΠΌΠΎ ΡΠ΅Π³ΠΎΠ²Π° ΠΏΠΎΡΠ°.
ΠΠ° ΡΠ°ΠΌ ΠΎΠ²Π°ΠΊΠΎ Π½Π°ΠΏΠΈΡΠ°ΠΎ () => app.store.keys
, ΠΎΠ½Π΄Π° ΡΠ΅ ΠΎΠΏΠ΅Ρ Π½ΠΈΡΡΠ° Π½Π΅ Π±ΠΈ Π΄Π΅ΡΠΈΠ»ΠΎ, ΠΏΠΎΡΡΠΎ ΡΠ΅ ΠΏΡΠΈΠ»ΠΈΠΊΠΎΠΌ Π΄ΠΎΠ΄Π°Π²Π°ΡΠ°/ΡΠΊΠ»Π°ΡΠ°ΡΠ° Π΅Π»Π΅ΠΌΠ΅Π½Π°ΡΠ° Π½ΠΈΠ·Π° ΡΠ΅ΡΠ΅ΡΠ΅Π½ΡΠ° Π½Π° ΡΠ΅Π³Π° Π½Π΅ΡΠ΅ ΠΏΡΠΎΠΌΠ΅Π½ΠΈΡΠΈ.
ΠΠΎΠ±ΠΊ ΠΏΠΎ ΠΏΡΠ²ΠΈ ΠΏΡΡ Π΄Π΅Π»ΡΡΠ΅ ΠΊΠ°ΠΎ ΡΠ΅Π»Π΅ΠΊΡΠΎΡ ΠΈ ΠΏΡΠ°ΡΠΈ ΡΠ°ΠΌΠΎ ΠΏΠΎΡΠΌΠ°ΡΡΠ°Π½Π΅ Π²ΡΠ΅Π΄Π½ΠΎΡΡΠΈ ΠΊΠΎΡΠΈΠΌΠ° ΡΠΌΠΎ ΠΏΡΠΈΡΡΡΠΏΠΈΠ»ΠΈ. ΠΠ²ΠΎ ΡΠ΅ ΡΠ°Π΄ΠΈ ΠΏΡΠ΅ΠΊΠΎ ΠΏΡΠΎΠΊΠΈ Π³Π΅ΡΡΠ΅ΡΠ°. Π‘ΡΠΎΠ³Π° ΡΠ΅ ΠΎΠ²Π΄Π΅ ΠΊΠΎΡΠΈΡΡΠΈ ΡΠ³ΡΠ°ΡΠ΅Π½Π° ΡΡΠ½ΠΊΡΠΈΡΠ° toJS
. ΠΡΠ°ΡΠ° Π½ΠΎΠ²ΠΈ ΠΎΠ±ΡΠ΅ΠΊΠ°Ρ ΡΠ° ΡΠ²ΠΈΠΌ ΠΏΡΠΎΠΊΡΠΈΡΠΈΠΌΠ° Π·Π°ΠΌΠ΅ΡΠ΅Π½ΠΈΠΌ ΠΎΡΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈΠΌ ΠΏΠΎΡΠΈΠΌΠ°. Π’ΠΎΠΊΠΎΠΌ ΠΈΠ·Π²ΡΡΠ°Π²Π°ΡΠ°, ΡΠΈΡΠ° ΡΠ²Π° ΠΏΠΎΡΠ° ΠΎΠ±ΡΠ΅ΠΊΡΠ° - ΡΡΠΎΠ³Π° ΡΠ΅ ΠΏΠΎΠΊΡΠ΅ΡΡ Π³Π΅ΡΡΠ΅ΡΠΈ.
Π£ ΠΈΡΠΊΠ°ΡΡΡΠΎΡ ΠΊΠΎΠ½Π·ΠΎΠ»ΠΈ ΡΠ΅ΠΌΠΎ ΠΏΠΎΠ½ΠΎΠ²ΠΎ Π΄ΠΎΠ΄Π°ΡΠΈ Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ ΠΊΡΡΡΠ΅Π²Π°. ΠΠ²Π°Ρ ΠΏΡΡ ΡΡ ΡΠ°ΠΊΠΎΡΠ΅ Π·Π°Π²ΡΡΠΈΠ»ΠΈ Ρ Π»ΠΎΡΠ°Π»Π‘ΡΠΎΡΠ°Π³Π΅:
ΠΠ°Π΄Π° ΡΠ΅ ΠΏΠΎΠ·Π°Π΄ΠΈΠ½ΡΠΊΠ° ΡΡΡΠ°Π½ΠΈΡΠ° ΠΏΠΎΠ½ΠΎΠ²ΠΎ ΡΡΠΈΡΠ°, ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡΠ΅ ΠΎΡΡΠ°ΡΡ Π½Π° ΠΌΠ΅ΡΡΡ.
Π‘Π²ΠΈ ΠΊΠΎΠ΄ΠΎΠ²ΠΈ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ΅ Π΄ΠΎ ΠΎΠ²Π΅ ΡΠ°ΡΠΊΠ΅ ΡΠ΅ ΠΌΠΎΠ³Ρ Π²ΠΈΠ΄Π΅ΡΠΈ
Π‘ΠΈΠ³ΡΡΠ½ΠΎ ΡΠΊΠ»Π°Π΄ΠΈΡΡΠ΅ΡΠ΅ ΠΏΡΠΈΠ²Π°ΡΠ½ΠΈΡ ΠΊΡΡΡΠ΅Π²Π°
Π§ΡΠ²Π°ΡΠ΅ ΠΏΡΠΈΠ²Π°ΡΠ½ΠΈΡ ΠΊΡΡΡΠ΅Π²Π° Ρ ΡΠΈΡΡΠΎΠΌ ΡΠ΅ΠΊΡΡΡ Π½ΠΈΡΠ΅ Π±Π΅Π·Π±Π΅Π΄Π½ΠΎ: ΡΠ²Π΅ΠΊ ΠΏΠΎΡΡΠΎΡΠΈ ΡΠ°Π½ΡΠ° Π΄Π° Π±ΡΠ΄Π΅ΡΠ΅ Ρ Π°ΠΊΠΎΠ²Π°Π½ΠΈ, Π΄Π° Π΄ΠΎΠ±ΠΈΡΠ΅ΡΠ΅ ΠΏΡΠΈΡΡΡΠΏ ΡΠ²ΠΎΠΌ ΡΠ°ΡΡΠ½Π°ΡΡ ΠΈ ΡΠ°ΠΊΠΎ Π΄Π°ΡΠ΅. Π‘ΡΠΎΠ³Π° ΡΠ΅ΠΌΠΎ Ρ Π»ΠΎΡΠ°Π»Π‘ΡΠΎΡΠ°Π³Π΅ ΡΡΠ²Π°ΡΠΈ ΠΊΡΡΡΠ΅Π²Π΅ Ρ ΡΠΈΡΡΠΎΠ²Π°Π½ΠΎΠΌ ΠΎΠ±Π»ΠΈΠΊΡ.
ΠΠ° Π²Π΅ΡΡ ΡΠΈΠ³ΡΡΠ½ΠΎΡΡ, Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠΈ ΡΠ΅ΠΌΠΎ Π΄ΠΎΠ΄Π°ΡΠΈ Π·Π°ΠΊΡΡΡΠ°Π½ΠΎ ΡΡΠ°ΡΠ΅ Ρ ΠΊΠΎΡΠ΅ΠΌ ΡΠΎΠΏΡΡΠ΅ Π½Π΅ΡΠ΅ Π±ΠΈΡΠΈ ΠΏΡΠΈΡΡΡΠΏΠ° ΠΊΡΡΡΠ΅Π²ΠΈΠΌΠ°. ΠΡΡΠΎΠΌΠ°ΡΡΠΊΠΈ ΡΠ΅ΠΌΠΎ ΠΏΡΠ΅Π±Π°ΡΠΈΡΠΈ Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΡ Ρ Π·Π°ΠΊΡΡΡΠ°Π½ΠΎ ΡΡΠ°ΡΠ΅ Π·Π±ΠΎΠ³ ΠΈΡΡΠ΅ΠΊΠ° Π²ΡΠ΅ΠΌΠ΅Π½Π°.
ΠΠΎΠ±ΠΊ Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡΡΠ°Π²Π° Π΄Π° ΡΠ°ΡΡΠ²Π°ΡΠ΅ ΡΠ°ΠΌΠΎ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»Π½ΠΈ ΡΠΊΡΠΏ ΠΏΠΎΠ΄Π°ΡΠ°ΠΊΠ°, Π° ΠΎΡΡΠ°ΡΠ°ΠΊ ΡΠ΅ Π°ΡΡΠΎΠΌΠ°ΡΡΠΊΠΈ ΠΈΠ·ΡΠ°ΡΡΠ½Π°Π²Π° Π½Π° ΠΎΡΠ½ΠΎΠ²Ρ ΡΠ΅Π³Π°. Π’ΠΎ ΡΡ ΡΠ°ΠΊΠΎΠ·Π²Π°Π½Π° ΠΈΠ·ΡΠ°ΡΡΠ½Π°ΡΠ° ΡΠ²ΠΎΡΡΡΠ²Π°. ΠΠ½ΠΈ ΡΠ΅ ΠΌΠΎΠ³Ρ ΡΠΏΠΎΡΠ΅Π΄ΠΈΡΠΈ ΡΠ° ΠΏΡΠΈΠΊΠ°Π·ΠΈΠΌΠ° Ρ Π±Π°Π·Π°ΠΌΠ° ΠΏΠΎΠ΄Π°ΡΠ°ΠΊΠ°:
import {observable, action} from 'mobx';
import {setupDnode} from "./utils/setupDnode";
// Π£ΡΠΈΠ»ΠΈΡΡ Π΄Π»Ρ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΠ³ΠΎ ΡΠΈΡΡΠΎΠ²Π°Π½ΠΈΡ ΡΡΡΠΎΠΊ. ΠΡΠΏΠΎΠ»ΡΠ·ΡΡΡ crypto-js
import {encrypt, decrypt} from "./utils/cryptoUtils";
export class SignerApp {
constructor(initState = {}) {
this.store = observable.object({
// Π₯ΡΠ°Π½ΠΈΠΌ ΠΏΠ°ΡΠΎΠ»Ρ ΠΈ Π·Π°ΡΠΈΡΡΠΎΠ²Π°Π½Π½ΡΠ΅ ΠΊΠ»ΡΡΠΈ. ΠΡΠ»ΠΈ ΠΏΠ°ΡΠΎΠ»Ρ null - ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ locked
password: null,
vault: initState.vault,
// ΠΠ΅ΡΡΠ΅ΡΡ Π΄Π»Ρ Π²ΡΡΠΈΡΠ»ΠΈΠΌΡΡ
ΠΏΠΎΠ»Π΅ΠΉ. ΠΠΎΠΆΠ½ΠΎ ΠΏΡΠΎΠ²Π΅ΡΡΠΈ Π°Π½Π°Π»ΠΎΠ³ΠΈΡ Ρ view Π² Π±Π΄.
get locked(){
return this.password == null
},
get keys(){
return this.locked ?
undefined :
SignerApp._decryptVault(this.vault, this.password)
},
get initialized(){
return this.vault !== undefined
}
})
}
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΏΡΡΡΠΎΠ³ΠΎ Ρ
ΡΠ°Π½ΠΈΠ»ΠΈΡΠ° Π½ΠΎΠ²ΡΠΌ ΠΏΠ°ΡΠΎΠ»Π΅ΠΌ
@action
initVault(password){
this.store.vault = SignerApp._encryptVault([], password)
}
@action
lock() {
this.store.password = null
}
@action
unlock(password) {
this._checkPassword(password);
this.store.password = password
}
@action
addKey(key) {
this._checkLocked();
this.store.vault = SignerApp._encryptVault(this.store.keys.concat(key), this.store.password)
}
@action
removeKey(index) {
this._checkLocked();
this.store.vault = SignerApp._encryptVault([
...this.store.keys.slice(0, index),
...this.store.keys.slice(index + 1)
],
this.store.password
)
}
... // ΠΊΠΎΠ΄ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΡ ΠΈ api
// private
_checkPassword(password) {
SignerApp._decryptVault(this.store.vault, password);
}
_checkLocked() {
if (this.store.locked){
throw new Error('App is locked')
}
}
// ΠΠ΅ΡΠΎΠ΄Ρ Π΄Π»Ρ ΡΠΈΡΡΠΎΠ²ΠΊΠΈ/Π΄Π΅ΡΠΈΡΡΠΎΠ²ΠΊΠΈ Ρ
ΡΠ°Π½ΠΈΠ»ΠΈΡΠ°
static _encryptVault(obj, pass){
const jsonString = JSON.stringify(obj)
return encrypt(jsonString, pass)
}
static _decryptVault(str, pass){
if (str === undefined){
throw new Error('Vault not initialized')
}
try {
const jsonString = decrypt(str, pass)
return JSON.parse(jsonString)
}catch (e) {
throw new Error('Wrong password')
}
}
}
Π‘Π°Π΄Π° ΡΡΠ²Π°ΠΌΠΎ ΡΠ°ΠΌΠΎ ΡΠΈΡΡΠΎΠ²Π°Π½Π΅ ΠΊΡΡΡΠ΅Π²Π΅ ΠΈ Π»ΠΎΠ·ΠΈΠ½ΠΊΡ. Π‘Π²Π΅ ΠΎΡΡΠ°Π»ΠΎ ΡΠ΅ ΠΏΡΠΎΡΠ°ΡΡΠ½Π°ΡΠΎ. ΠΡΡΠΈΠΌΠΎ ΠΏΡΠ΅Π½ΠΎΡ Ρ Π·Π°ΠΊΡΡΡΠ°Π½ΠΎ ΡΡΠ°ΡΠ΅ ΡΠΊΠ»Π°ΡΠ°ΡΠ΅ΠΌ Π»ΠΎΠ·ΠΈΠ½ΠΊΠ΅ ΠΈΠ· ΡΡΠ°ΡΠ°. ΠΠ°Π²Π½ΠΈ ΠΠΠ ΡΠ°Π΄Π° ΠΈΠΌΠ° ΠΌΠ΅ΡΠΎΠ΄ Π·Π° ΠΈΠ½ΠΈΡΠΈΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡΡ ΡΠΊΠ»Π°Π΄ΠΈΡΡΠ°.
ΠΠ°ΠΏΠΈΡΠ°Π½ΠΎ Π·Π° ΡΠΈΡΡΠΎΠ²Π°ΡΠ΅
import CryptoJS from 'crypto-js'
// ΠΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ Π΄Π»Ρ ΠΎΡΠ»ΠΎΠΆΠ½Π΅Π½ΠΈΡ ΠΏΠΎΠ΄Π±ΠΎΡΠ° ΠΏΠ°ΡΠΎΠ»Ρ ΠΏΠ΅ΡΠ΅Π±ΠΎΡΠΎΠΌ. ΠΠ° ΠΊΠ°ΠΆΠ΄ΡΠΉ Π²Π°ΡΠΈΠ°Π½Ρ ΠΏΠ°ΡΠΎΠ»Ρ Π·Π»ΠΎΡΠΌΡΡΠ»Π΅Π½Π½ΠΈΠΊΡ ΠΏΡΠΈΠ΄Π΅ΡΡΡ ΡΠ΄Π΅Π»Π°ΡΡ 5000 Ρ
Π΅ΡΠ΅ΠΉ
function strengthenPassword(pass, rounds = 5000) {
while (rounds-- > 0){
pass = CryptoJS.SHA256(pass).toString()
}
return pass
}
export function encrypt(str, pass){
const strongPass = strengthenPassword(pass);
return CryptoJS.AES.encrypt(str, strongPass).toString()
}
export function decrypt(str, pass){
const strongPass = strengthenPassword(pass)
const decrypted = CryptoJS.AES.decrypt(str, strongPass);
return decrypted.toString(CryptoJS.enc.Utf8)
}
ΠΡΠ΅Π³Π»Π΅Π΄Π°Ρ ΠΈΠΌΠ° Π½Π΅Π°ΠΊΡΠΈΠ²Π½ΠΈ ΠΠΠ ΠΏΡΠ΅ΠΊΠΎ ΠΊΠΎΡΠ΅Π³ ΡΠ΅ ΠΌΠΎΠΆΠ΅ΡΠ΅ ΠΏΡΠ΅ΡΠΏΠ»Π°ΡΠΈΡΠΈ Π½Π° Π΄ΠΎΠ³Π°ΡΠ°Ρ - ΠΏΡΠΎΠΌΠ΅Π½Π΅ ΡΡΠ°ΡΠ°. ΠΡΠΆΠ°Π²Π°, ΡΡ
ΠΎΠ΄Π½ΠΎ ΡΠΎΠΌΠ΅, ΠΌΠΎΠΆΠ΅ Π±ΠΈΡΠΈ idle
, active
ΠΈ locked
. ΠΠ° ΠΌΠΈΡΠΎΠ²Π°ΡΠ΅ ΠΌΠΎΠΆΠ΅ΡΠ΅ ΠΏΠΎΠ΄Π΅ΡΠΈΡΠΈ Π²ΡΠ΅ΠΌΠ΅Π½ΡΠΊΠΎ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅ΡΠ΅, Π° Π·Π°ΠΊΡΡΡΠ°Π½ΠΎ ΡΠ΅ ΠΏΠΎΡΡΠ°Π²ΡΠ° ΠΊΠ°Π΄Π° ΡΠ΅ ΡΠ°ΠΌ ΠΠ‘ Π±Π»ΠΎΠΊΠΈΡΠ°Π½. Π’Π°ΠΊΠΎΡΠ΅ ΡΠ΅ΠΌΠΎ ΠΏΡΠΎΠΌΠ΅Π½ΠΈΡΠΈ ΡΠ΅Π»Π΅ΠΊΡΠΎΡ Π·Π° ΡΡΠ²Π°ΡΠ΅ Ρ Π»ΠΎΡΠ°Π»Π‘ΡΠΎΡΠ°Π³Π΅:
import {reaction, toJS} from 'mobx';
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {SignerApp} from "./SignerApp";
import {loadState, saveState} from "./utils/localStorage";
const DEV_MODE = process.env.NODE_ENV !== 'production';
const IDLE_INTERVAL = 30;
setupApp();
function setupApp() {
const initState = loadState();
const app = new SignerApp(initState);
if (DEV_MODE) {
global.app = app;
}
// Π’Π΅ΠΏΠ΅ΡΡ ΠΌΡ ΡΠ²Π½ΠΎ ΡΠ·ΡΠ²Π°Π΅ΠΌ ΠΏΠΎΠ»Π΅, ΠΊΠΎΡΠΎΡΠΎΠΌΡ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΎΠΈΡΡ
ΠΎΠ΄ΠΈΡΡ Π΄ΠΎΡΡΡΠΏ, reaction ΠΎΡΡΠ°Π±ΠΎΡΠ°Π΅Ρ Π½ΠΎΡΠΌΠ°Π»ΡΠ½ΠΎ
reaction(
() => ({
vault: app.store.vault
}),
saveState
);
// Π’Π°ΠΉΠΌΠ°ΡΡ Π±Π΅Π·Π΄Π΅ΠΉΡΡΠ²ΠΈΡ, ΠΊΠΎΠ³Π΄Π° ΡΡΠ°Π±ΠΎΡΠ°Π΅Ρ ΡΠΎΠ±ΡΡΠΈΠ΅
extensionApi.idle.setDetectionInterval(IDLE_INTERVAL);
// ΠΡΠ»ΠΈ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π·Π°Π»ΠΎΡΠΈΠ» ΡΠΊΡΠ°Π½ ΠΈΠ»ΠΈ Π±Π΅Π·Π΄Π΅ΠΉΡΡΠ²ΠΎΠ²Π°Π» Π² ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ ΡΠΊΠ°Π·Π°Π½Π½ΠΎΠ³ΠΎ ΠΈΠ½ΡΠ΅ΡΠ²Π°Π»Π° Π»ΠΎΡΠΈΠΌ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
extensionApi.idle.onStateChanged.addListener(state => {
if (['locked', 'idle'].indexOf(state) > -1) {
app.lock()
}
});
// Connect to other contexts
extensionApi.runtime.onConnect.addListener(connectRemote);
function connectRemote(remotePort) {
const processName = remotePort.name;
const portStream = new PortStream(remotePort);
if (processName === 'contentscript') {
const origin = remotePort.sender.url
app.connectPage(portStream, origin)
} else {
app.connectPopup(portStream)
}
}
}
ΠΠΎΠ΄ ΠΏΡΠ΅ ΠΎΠ²ΠΎΠ³ ΠΊΠΎΡΠ°ΠΊΠ° ΡΠ΅
Π’ΡΠ°Π½ΡΠ°ΠΊΡΠΈΡΠ°
ΠΠ°ΠΊΠ»Π΅, Π΄ΠΎΠ»Π°Π·ΠΈΠΌΠΎ Π΄ΠΎ Π½Π°ΡΠ²Π°ΠΆΠ½ΠΈΡΠ΅ ΡΡΠ²Π°ΡΠΈ: ΠΊΡΠ΅ΠΈΡΠ°ΡΠ° ΠΈ ΠΏΠΎΡΠΏΠΈΡΠΈΠ²Π°ΡΠ° ΡΡΠ°Π½ΡΠ°ΠΊΡΠΈΡΠ° Π½Π° Π±Π»ΠΎΠΊΡΠ΅ΡΠ½Ρ. ΠΠΎΡΠΈΡΡΠΈΡΠ΅ΠΌΠΎ ΠΠΠΠΠ‘ Π±Π»ΠΎΡΠΊΡΡ
Π°ΠΈΠ½ ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΡ
ΠΡΠ²ΠΎ, Π΄ΠΎΠ΄Π°ΡΠΌΠΎ ΡΡΠ°ΡΡ Π½ΠΈΠ· ΠΏΠΎΡΡΠΊΠ° ΠΊΠΎΡΠ΅ ΡΡΠ΅Π±Π° ΠΏΠΎΡΠΏΠΈΡΠ°ΡΠΈ, Π° Π·Π°ΡΠΈΠΌ Π΄ΠΎΠ΄Π°ΠΌΠΎ ΠΌΠ΅ΡΠΎΠ΄Π΅ Π·Π° Π΄ΠΎΠ΄Π°Π²Π°ΡΠ΅ Π½ΠΎΠ²Π΅ ΠΏΠΎΡΡΠΊΠ΅, ΠΏΠΎΡΠ²ΡΡΠΈΠ²Π°ΡΠ΅ ΠΏΠΎΡΠΏΠΈΡΠ° ΠΈ ΠΎΠ΄Π±ΠΈΡΠ°ΡΠ΅:
import {action, observable, reaction} from 'mobx';
import uuid from 'uuid/v4';
import {signTx} from '@waves/waves-transactions'
import {setupDnode} from "./utils/setupDnode";
import {decrypt, encrypt} from "./utils/cryptoUtils";
export class SignerApp {
...
@action
newMessage(data, origin) {
// ΠΠ»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ ΡΠΎΠ·Π΄Π°Π΅ΠΌ ΠΌΠ΅ΡΠ°Π΄Π°Π½Π½ΡΠ΅ Ρ id, ΡΡΠ°ΡΡΡΠΎΠΌ, Π²ΡΡΠ΅ΠΌΠ΅Π½Π΅ΠΌ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΈ ΡΠ΄.
const message = observable.object({
id: uuid(), // ΠΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡ, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡ uuid
origin, // Origin Π±ΡΠ΄Π΅ΠΌ Π²ΠΏΠΎΡΠ»Π΅Π΄ΡΡΠ²ΠΈΠΈ ΠΏΠΎΠΊΠ°Π·ΡΠ²Π°ΡΡ Π² ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ΅
data, //
status: 'new', // Π‘ΡΠ°ΡΡΡΠΎΠ² Π±ΡΠ΄Π΅Ρ ΡΠ΅ΡΡΡΠ΅: new, signed, rejected ΠΈ failed
timestamp: Date.now()
});
console.log(`new message: ${JSON.stringify(message, null, 2)}`);
this.store.messages.push(message);
// ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅ΠΌ ΠΏΡΠΎΠΌΠΈΡ Π²Π½ΡΡΡΠΈ ΠΊΠΎΡΠΎΡΠΎΠ³ΠΎ mobx ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΡ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ. ΠΠ°ΠΊ ΡΠΎΠ»ΡΠΊΠΎ ΡΡΠ°ΡΡΡ ΠΏΠΎΠΌΠ΅Π½ΡΠ΅ΡΡΡ ΠΌΡ Π·Π°ΡΠ΅Π·ΠΎΠ»Π²ΠΈΠΌ Π΅Π³ΠΎ
return new Promise((resolve, reject) => {
reaction(
() => message.status, //ΠΡΠ΄Π΅ΠΌ ΠΎΠ±ΡΠ΅ΡΠ²ΠΈΡΡ ΡΡΠ°ΡΡΡ ΡΠΎΠΎΠ±ΡΠ΅Π½Ρ
(status, reaction) => { // Π²ΡΠΎΡΠΎΠΉ Π°ΡΠ³ΡΠΌΠ΅Π½Ρ ΡΡΠΎ ΡΡΡΠ»ΠΊΠ° Π½Π° ΡΠ°ΠΌ reaction, ΡΡΠΎΠ±Ρ Π΅Π³ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π±ΡΠ»ΠΎ ΡΠ½ΠΈΡΡΠΎΠΆΡΡ Π²Π½ΡΡΡΠΈ Π²ΡΠ·ΠΎΠ²Π°
switch (status) {
case 'signed':
resolve(message.data);
break;
case 'rejected':
reject(new Error('User rejected message'));
break;
case 'failed':
reject(new Error(message.err.message));
break;
default:
return
}
reaction.dispose()
}
)
})
}
@action
approve(id, keyIndex = 0) {
const message = this.store.messages.find(msg => msg.id === id);
if (message == null) throw new Error(`No msg with id:${id}`);
try {
message.data = signTx(message.data, this.store.keys[keyIndex]);
message.status = 'signed'
} catch (e) {
message.err = {
stack: e.stack,
message: e.message
};
message.status = 'failed'
throw e
}
}
@action
reject(id) {
const message = this.store.messages.find(msg => msg.id === id);
if (message == null) throw new Error(`No msg with id:${id}`);
message.status = 'rejected'
}
...
}
ΠΠ°Π΄Π° ΠΏΡΠΈΠΌΠΈΠΌΠΎ Π½ΠΎΠ²Ρ ΠΏΠΎΡΡΠΊΡ, Π΄ΠΎΠ΄Π°ΡΠ΅ΠΌΠΎ ΡΠΎΡ ΠΌΠ΅ΡΠ°ΠΏΠΎΠ΄Π°ΡΠΊΠ΅, ΡΡΠ°Π΄ΠΈΡΠ΅ observable
ΠΈ Π΄ΠΎΠ΄Π°ΡΠΈ Ρ store.messages
.
ΠΠΊΠΎ ΡΠΎ Π½Π΅ ΡΡΠ°Π΄ΠΈΡΠ΅ observable
ΡΡΡΠ½ΠΎ, ΠΎΠ½Π΄Π° ΡΠ΅ ΠΌΠΎΠ±ΠΊ ΡΠΎ ΡΡΠ°Π΄ΠΈΡΠΈ ΡΠ°ΠΌ ΠΊΠ°Π΄Π° Π΄ΠΎΠ΄Π°ΡΠ΅ ΠΏΠΎΡΡΠΊΠ΅ Ρ Π½ΠΈΠ·. ΠΠ΅ΡΡΡΠΈΠΌ, ΠΊΡΠ΅ΠΈΡΠ°ΡΠ΅ Π½ΠΎΠ²ΠΈ ΠΎΠ±ΡΠ΅ΠΊΠ°Ρ Π½Π° ΠΊΠΎΡΠΈ Π½Π΅ΡΠ΅ΠΌΠΎ ΠΈΠΌΠ°ΡΠΈ ΡΠ΅ΡΠ΅ΡΠ΅Π½ΡΡ, Π°Π»ΠΈ ΡΠ΅ Π½Π°ΠΌ ΡΡΠ΅Π±Π°ΡΠΈ Π·Π° ΡΠ»Π΅Π΄Π΅ΡΠΈ ΠΊΠΎΡΠ°ΠΊ.
ΠΠ°ΡΠΈΠΌ Π²ΡΠ°ΡΠ°ΠΌΠΎ ΠΎΠ±Π΅ΡΠ°ΡΠ΅ ΠΊΠΎΡΠ΅ ΡΠ΅ ΡΠ΅ΡΠ°Π²Π° ΠΊΠ°Π΄Π° ΡΠ΅ ΡΡΠ°ΡΡΡ ΠΏΠΎΡΡΠΊΠ΅ ΠΏΡΠΎΠΌΠ΅Π½ΠΈ. Π‘ΡΠ°ΡΡΡ ΡΠ΅ ΠΏΡΠ°ΡΠΈ ΡΠ΅Π°ΠΊΡΠΈΡΠΎΠΌ, ΠΊΠΎΡΠ° ΡΠ΅ ΡΠ΅ βΡΠ±ΠΈΡΠΈβ ΠΊΠ°Π΄Π° ΡΠ΅ ΡΡΠ°ΡΡΡ ΠΏΡΠΎΠΌΠ΅Π½ΠΈ.
Π¨ΠΈΡΡΠ° ΠΌΠ΅ΡΠΎΠ΄Π΅ approve
ΠΈ reject
Π²ΡΠ»ΠΎ ΡΠ΅Π΄Π½ΠΎΡΡΠ°Π²Π½ΠΎ: ΡΠ΅Π΄Π½ΠΎΡΡΠ°Π²Π½ΠΎ ΠΌΠ΅ΡΠ°ΠΌΠΎ ΡΡΠ°ΡΡΡ ΠΏΠΎΡΡΠΊΠ΅, Π½Π°ΠΊΠΎΠ½ ΡΡΠΎ ΡΠ΅ ΠΏΠΎΡΠΏΠΈΡΠ΅ΠΌΠΎ Π°ΠΊΠΎ ΡΠ΅ ΠΏΠΎΡΡΠ΅Π±Π½ΠΎ.
Π‘ΡΠ°Π²ΡΠ°ΠΌΠΎ ΠΠΏΠΏΡΠΎΠ²Π΅ ΠΈ Π Π΅ΡΠ΅ΡΡ Ρ Π£Π ΠΠΠ, Π½Π΅Π²ΠΠ΅ΡΡΠ°Π³Π΅ Ρ ΠΠΠ ΡΡΡΠ°Π½ΠΈΡΠ΅:
export class SignerApp {
...
popupApi() {
return {
addKey: async (key) => this.addKey(key),
removeKey: async (index) => this.removeKey(index),
lock: async () => this.lock(),
unlock: async (password) => this.unlock(password),
initVault: async (password) => this.initVault(password),
approve: async (id, keyIndex) => this.approve(id, keyIndex),
reject: async (id) => this.reject(id)
}
}
pageApi(origin) {
return {
signTransaction: async (txParams) => this.newMessage(txParams, origin)
}
}
...
}
Π‘Π°Π΄Π° ΠΏΠΎΠΊΡΡΠ°ΡΠΌΠΎ Π΄Π° ΠΏΠΎΡΠΏΠΈΡΠ΅ΠΌΠΎ ΡΡΠ°Π½ΡΠ°ΠΊΡΠΈΡΡ ΡΠ° Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠΎΠΌ:
ΠΠ΅Π½Π΅ΡΠ°Π»Π½ΠΎ, ΡΠ²Π΅ ΡΠ΅ ΡΠΏΡΠ΅ΠΌΠ½ΠΎ, ΠΎΡΡΠ°ΡΠ΅ ΡΠ°ΠΌΠΎ
UI
ΠΠ½ΡΠ΅ΡΡΠ΅ΡΡΡ ΡΠ΅ ΠΏΠΎΡΡΠ΅Π±Π°Π½ ΠΏΡΠΈΡΡΡΠΏ ΡΡΠ°ΡΡ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ΅. ΠΠ° ΡΡΡΠ°Π½ΠΈ ΠΊΠΎΡΠΈΡΠ½ΠΈΡΠΊΠΎΠ³ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΡΡΠ° ΡΠ΅ΠΌΠΎ ΡΡΠ°Π΄ΠΈΡΠΈ observable
ΡΡΠ°ΡΠ΅ ΠΈ Π΄ΠΎΠ΄Π°ΡΡΠ΅ ΡΡΠ½ΠΊΡΠΈΡΡ Ρ ΠΠΠ ΠΊΠΎΡΠ° ΡΠ΅ ΠΏΡΠΎΠΌΠ΅Π½ΠΈΡΠΈ ΠΎΠ²ΠΎ ΡΡΠ°ΡΠ΅. ΠΠ° Π΄ΠΎΠ΄Π°ΠΌΠΎ observable
Π½Π° ΠΠΠ ΠΎΠ±ΡΠ΅ΠΊΠ°Ρ ΠΏΡΠΈΠΌΡΠ΅Π½ ΠΈΠ· ΠΏΠΎΠ·Π°Π΄ΠΈΠ½Π΅:
import {observable} from 'mobx'
import {extensionApi} from "./utils/extensionApi";
import {PortStream} from "./utils/PortStream";
import {cbToPromise, setupDnode, transformMethods} from "./utils/setupDnode";
import {initApp} from "./ui/index";
const DEV_MODE = process.env.NODE_ENV !== 'production';
setupUi().catch(console.error);
async function setupUi() {
// ΠΠΎΠ΄ΠΊΠ»ΡΡΠ°Π΅ΠΌΡΡ ΠΊ ΠΏΠΎΡΡΡ, ΡΠΎΠ·Π΄Π°Π΅ΠΌ ΠΈΠ· Π½Π΅Π³ΠΎ ΡΡΡΠΈΠΌ
const backgroundPort = extensionApi.runtime.connect({name: 'popup'});
const connectionStream = new PortStream(backgroundPort);
// Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΠΏΡΡΡΠΎΠΉ observable Π΄Π»Ρ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ background'a
let backgroundState = observable.object({});
const api = {
//ΠΡΠ΄Π°Π΅ΠΌ Π±Π΅ΠΊΠ³ΡΠ°ΡΠ½Π΄Ρ ΡΡΠ½ΠΊΡΠΈΡ, ΠΊΠΎΡΠΎΡΠ°Ρ Π±ΡΠ΄Π΅Ρ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡΡ observable
updateState: async state => {
Object.assign(backgroundState, state)
}
};
// ΠΠ΅Π»Π°Π΅ΠΌ RPC ΠΎΠ±ΡΠ΅ΠΊΡ
const dnode = setupDnode(connectionStream, api);
const background = await new Promise(resolve => {
dnode.once('remote', remoteApi => {
resolve(transformMethods(cbToPromise, remoteApi))
})
});
// ΠΠΎΠ±Π°Π²Π»ΡΠ΅ΠΌ Π² background observable ΡΠΎ ΡΡΠ΅ΠΉΡΠΎΠΌ
background.state = backgroundState;
if (DEV_MODE) {
global.background = background;
}
// ΠΠ°ΠΏΡΡΠΊ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ°
await initApp(background)
}
ΠΠ° ΠΊΡΠ°ΡΡ ΠΏΠΎΡΠΈΡΠ΅ΠΌΠΎ Π΄Π° ΠΏΡΠΈΠΊΠ°Π·ΡΡΠ΅ΠΌΠΎ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΡΡ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ΅. ΠΠ²ΠΎ ΡΠ΅ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ° Π·Π° ΡΠ΅Π°ΠΊΡΠΈΡΡ. ΠΠΎΠ·Π°Π΄ΠΈΠ½ΡΠΊΠΈ ΠΎΠ±ΡΠ΅ΠΊΠ°Ρ ΡΠ΅ ΡΠ΅Π΄Π½ΠΎΡΡΠ°Π²Π½ΠΎ ΠΏΡΠ΅Π½ΠΎΡΠΈ ΠΏΠΎΠΌΠΎΡΡ ΡΠ΅ΠΊΠ²ΠΈΠ·ΠΈΡΠ°. ΠΠΈΠ»ΠΎ Π±ΠΈ ΠΈΡΠΏΡΠ°Π²Π½ΠΎ, Π½Π°ΡΠ°Π²Π½ΠΎ, Π½Π°ΠΏΡΠ°Π²ΠΈΡΠΈ ΠΏΠΎΡΠ΅Π±Π°Π½ ΡΠ΅ΡΠ²ΠΈΡ Π·Π° ΠΌΠ΅ΡΠΎΠ΄Π΅ ΠΈ ΠΏΡΠΎΠ΄Π°Π²Π½ΠΈΡΡ Π·Π° Π΄ΡΠΆΠ°Π²Ρ, Π°Π»ΠΈ Π·Π° ΠΏΠΎΡΡΠ΅Π±Π΅ ΠΎΠ²ΠΎΠ³ ΡΠ»Π°Π½ΠΊΠ° ΠΎΠ²ΠΎ ΡΠ΅ Π΄ΠΎΠ²ΠΎΡΠ½ΠΎ:
import {render} from 'react-dom'
import App from './App'
import React from "react";
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΡΠ΅ΠΌ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ background ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠΌ Π² ΠΊΠ°ΡΠ΅ΡΡ Π²Π΅ props
export async function initApp(background){
render(
<App background={background}/>,
document.getElementById('app-content')
);
}
Π‘Π° ΠΌΠΎΠ±ΠΊ-ΠΎΠΌ ΡΠ΅ Π²Π΅ΠΎΠΌΠ° Π»Π°ΠΊΠΎ Π·Π°ΠΏΠΎΡΠ΅ΡΠΈ ΡΠ΅Π½Π΄Π΅ΡΠΎΠ²Π°ΡΠ΅ ΠΊΠ°Π΄Π° ΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΈ ΠΏΡΠΎΠΌΠ΅Π½Π΅. ΠΠ΅Π΄Π½ΠΎΡΡΠ°Π²Π½ΠΎ ΠΎΠΊΠ°ΡΠΈΠΌΠΎ ΠΏΠΎΡΠΌΠ°ΡΡΠ°ΡΠ° Π΄Π΅ΠΊΠΎΡΠ°ΡΠ΅ΡΠ° ΡΠ° ΠΏΠ°ΠΊΠ΅ΡΠ°
import React, {Component, Fragment} from 'react'
import {observer} from "mobx-react";
import Init from './components/Initialize'
import Keys from './components/Keys'
import Sign from './components/Sign'
import Unlock from './components/Unlock'
@observer // Π£ ΠΠΎΠΌΠΏΠΎΠ½Π΅ΡΠ° Ρ ΡΡΠΈΠΌ Π΄Π΅ΠΊΠΎΡΠ°ΡΠΎΠΌ Π±ΡΠ΄Π΅Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ Π²ΡΠ·Π²Π°Π½ ΠΌΠ΅ΡΠΎΠ΄ render, Π΅ΡΠ»ΠΈ Π±ΡΠ΄ΡΡ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½Ρ observable Π½Π° ΠΊΠΎΡΠΎΡΡΠ΅ ΠΎΠ½ ΡΡΡΠ»Π°Π΅ΡΡΡ
export default class App extends Component {
// ΠΡΠ°Π²ΠΈΠ»ΡΠ½ΠΎ ΠΊΠΎΠ½Π΅ΡΠ½ΠΎ Π²ΡΠ½Π΅ΡΡΠΈ Π»ΠΎΠ³ΠΈΠΊΡ ΡΠ΅Π½Π΄Π΅ΡΠ° ΡΡΡΠ°Π½ΠΈΡ Π² ΡΠΎΡΡΠΈΠ½Π³ ΠΈ Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π²Π»ΠΎΠΆΠ΅Π½Π½ΡΠ΅ ΡΠ΅ΡΠ½Π°ΡΠ½ΡΠ΅ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΡ,
// ΠΈ ΠΏΡΠΈΠ²ΡΠ·ΡΠ²Π°ΡΡ observable ΠΈ ΠΌΠ΅ΡΠΎΠ΄Ρ background Π½Π΅ΠΏΠΎΡΡΠ΅Π΄ΡΡΠ²Π΅Π½Π½ΠΎ ΠΊ ΡΠ΅ΠΌ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°ΠΌ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΈΡ
ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡ
render() {
const {keys, messages, initialized, locked} = this.props.background.state;
const {lock, unlock, addKey, removeKey, initVault, deleteVault, approve, reject} = this.props.background;
return <Fragment>
{!initialized
?
<Init onInit={initVault}/>
:
locked
?
<Unlock onUnlock={unlock}/>
:
messages.length > 0
?
<Sign keys={keys} message={messages[messages.length - 1]} onApprove={approve} onReject={reject}/>
:
<Keys keys={keys} onAdd={addKey} onRemove={removeKey}/>
}
<div>
{!locked && <button onClick={() => lock()}>Lock App</button>}
{initialized && <button onClick={() => deleteVault()}>Delete all keys and init</button>}
</div>
</Fragment>
}
}
ΠΡΠ΅ΠΎΡΡΠ°Π»Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ΅ ΡΠ΅ ΠΌΠΎΠ³Ρ Π²ΠΈΠ΄Π΅ΡΠΈ Ρ ΠΊΠΎΠ΄Ρ
Π‘Π°Π΄Π° Ρ ΠΊΠ»Π°ΡΠΈ Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ΅ ΡΡΠ΅Π±Π° Π΄Π° Π½Π°ΠΏΡΠ°Π²ΠΈΡΠ΅ ΡΠ΅Π»Π΅ΠΊΡΠΎΡ ΡΡΠ°ΡΠ° Π·Π° ΠΊΠΎΡΠΈΡΠ½ΠΈΡΠΊΠΈ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΡΡ ΠΈ ΠΎΠ±Π°Π²Π΅ΡΡΠΈΡΠ΅ Π£Π ΠΊΠ°Π΄Π° ΡΠ΅ ΠΏΡΠΎΠΌΠ΅Π½ΠΈ. ΠΠ° Π±ΠΈΡΠΌΠΎ ΡΠΎ ΡΡΠ°Π΄ΠΈΠ»ΠΈ, Π΄ΠΎΠ΄Π°ΡΠΌΠΎ ΠΌΠ΅ΡΠΎΠ΄ getState
ΠΈ reaction
Π·ΠΎΠ²Π΅ remote.updateState
:
import {action, observable, reaction} from 'mobx';
import uuid from 'uuid/v4';
import {signTx} from '@waves/waves-transactions'
import {setupDnode} from "./utils/setupDnode";
import {decrypt, encrypt} from "./utils/cryptoUtils";
export class SignerApp {
...
// public
getState() {
return {
keys: this.store.keys,
messages: this.store.newMessages,
initialized: this.store.initialized,
locked: this.store.locked
}
}
...
//
connectPopup(connectionStream) {
const api = this.popupApi();
const dnode = setupDnode(connectionStream, api);
dnode.once('remote', (remote) => {
// Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ reaction Π½Π° ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ ΡΡΠ΅ΠΉΡΠ°, ΠΊΠΎΡΠΎΡΡΠΉ ΡΠ΄Π΅Π»Π°Π΅Ρ Π²ΡΠ·ΠΎΠ²Π΅Ρ ΡΠ΄Π°Π»Π΅Π½Π½Ρ ΠΏΡΠΎΡΠ΅Π΄ΡΡΡ ΠΈ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ ΡΡΠ΅ΠΉΡ Π² ui ΠΏΡΠΎΡΠ΅ΡΡΠ΅
const updateStateReaction = reaction(
() => this.getState(),
(state) => remote.updateState(state),
// Π’ΡΠ΅ΡΡΠΈΠΌ Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΎΠΌ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅ΡΠ΅Π΄Π°Π²Π°ΡΡ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΡ. fireImmediatly Π·Π½Π°ΡΠΈΡ ΡΡΠΎ reaction Π²ΡΠΏΠΎΠ»Π½ΠΈΡΡΡΡ ΠΏΠ΅ΡΠ²ΡΠΉ ΡΠ°Π· ΡΡΠ°Π·Ρ.
// ΠΡΠΎ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎ, ΡΡΠΎΠ±Ρ ΠΏΠΎΠ»ΡΡΠΈΡΡ Π½Π°ΡΠ°Π»ΡΠ½ΠΎΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅. Delay ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ debounce
{fireImmediately: true, delay: 500}
);
// Π£Π΄Π°Π»ΠΈΠΌ ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΡ ΠΏΡΠΈ ΠΎΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΈ ΠΊΠ»ΠΈΠ΅Π½ΡΠ°
dnode.once('end', () => updateStateReaction.dispose())
})
}
...
}
ΠΡΠΈΠ»ΠΈΠΊΠΎΠΌ ΠΏΡΠΈΡΠ΅ΠΌΠ° ΠΏΡΠ΅Π΄ΠΌΠ΅ΡΠ° remote
ΡΠ΅ ΠΊΡΠ΅ΠΈΡΠ°Π½ reaction
Π΄Π° ΠΏΡΠΎΠΌΠ΅Π½ΠΈΡΠ΅ ΡΡΠ°ΡΠ΅ ΠΊΠΎΡΠ΅ ΠΏΠΎΠ·ΠΈΠ²Π° ΡΡΠ½ΠΊΡΠΈΡΡ Π½Π° ΡΡΡΠ°Π½ΠΈ ΠΊΠΎΡΠΈΡΠ½ΠΈΡΠΊΠΎΠ³ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΡΡΠ°.
ΠΠΎΡΠ»Π΅Π΄ΡΠΈ Π΄ΠΎΠ΄ΠΈΡ ΡΠ΅ Π΄ΠΎΠ΄Π°Π²Π°ΡΠ΅ ΠΏΡΠΈΠΊΠ°Π·Π° Π½ΠΎΠ²ΠΈΡ ΠΏΠΎΡΡΠΊΠ° Π½Π° ΠΈΠΊΠΎΠ½Ρ Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΠ΅:
function setupApp() {
...
// Reaction Π½Π° Π²ΡΡΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΡΠ΅ΠΊΡΡΠ° Π±Π΅Π΄ΠΆΠ°.
reaction(
() => app.store.newMessages.length > 0 ? app.store.newMessages.length.toString() : '',
text => extensionApi.browserAction.setBadgeText({text}),
{fireImmediately: true}
);
...
}
ΠΠ°ΠΊΠ»Π΅, Π°ΠΏΠ»ΠΈΠΊΠ°ΡΠΈΡΠ° ΡΠ΅ ΡΠΏΡΠ΅ΠΌΠ½Π°. ΠΠ΅Π± ΡΡΡΠ°Π½ΠΈΡΠ΅ ΠΌΠΎΠ³Ρ Π·Π°Ρ ΡΠ΅Π²Π°ΡΠΈ ΠΏΠΎΡΠΏΠΈΡ Π·Π° ΡΡΠ°Π½ΡΠ°ΠΊΡΠΈΡΠ΅:
ΠΠΎΠ΄ ΡΠ΅ Π΄ΠΎΡΡΡΠΏΠ°Π½ ΠΎΠ²Π΄Π΅
ΠΠ°ΠΊΡΡΡΠ°ΠΊ
ΠΠΊΠΎ ΡΡΠ΅ ΠΏΡΠΎΡΠΈΡΠ°Π»ΠΈ ΡΠ»Π°Π½Π°ΠΊ Π΄ΠΎ ΠΊΡΠ°ΡΠ°, Π°Π»ΠΈ ΠΈ Π΄Π°ΡΠ΅ ΠΈΠΌΠ°ΡΠ΅ ΠΏΠΈΡΠ°ΡΠ°, ΠΌΠΎΠΆΠ΅ΡΠ΅ ΠΈΡ
ΠΏΠΎΡΡΠ°Π²ΠΈΡΠΈ Π½Π°
Π Π°ΠΊΠΎ ΡΡΠ΅ Π·Π°ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠΎΠ²Π°Π½ΠΈ Π΄Π° ΠΏΠΎΠ³Π»Π΅Π΄Π°ΡΠ΅ ΠΊΠΎΠ΄ Π·Π° ΡΡΠ²Π°ΡΠ½Ρ Π΅ΠΊΡΡΠ΅Π½Π·ΠΈΡΡ, ΠΌΠΎΠΆΠ΅ΡΠ΅ ΠΏΡΠΎΠ½Π°ΡΠΈ ΠΎΠ²ΠΎ
Π¨ΠΈΡΡΠ°, ΡΠΏΡΠ΅ΠΌΠΈΡΡΠ΅ ΠΈ ΠΎΠΏΠΈΡ ΠΏΠΎΡΠ»Π° ΠΎΠ΄
ΠΠ·Π²ΠΎΡ: Π²Π²Π².Ρ Π°Π±Ρ.ΡΠΎΠΌ