{"id":33644,"date":"2019-10-31T21:53:55","date_gmt":"2019-10-31T18:53:55","guid":{"rendered":"https:\/\/prohoster.info\/blog\/pishem-bezopasnoe-brauzernoe-rasshirenie\/"},"modified":"2019-10-31T21:53:55","modified_gmt":"2019-10-31T18:53:55","slug":"pishem-bezopasnoe-brauzernoe-rasshirenie","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/pishem-bezopasnoe-brauzernoe-rasshirenie","title":{"rendered":"Sichere Browsererweiterungen entwickeln","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/a9c75919adc31f3aae36ffc2c3c9644d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043d\u043e\u0439 &#171;\u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439&#187; \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u0434\u043b\u044f \u0434\u0435\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u043e:<\/p>\n<p><\/p>\n<ul>\n<li>\u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043b\u043e\u0433\u0438\u043d\u0430\u043c\u0438 \u0438 \u043f\u0430\u0440\u043e\u043b\u044f\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443 \u0441\u0430\u043c\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0430 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0438\u0445 \u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430.<\/li>\n<li>\u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440. \u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d-\u0441\u0435\u0442\u0438, \u0433\u0434\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0438 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0434\u0430\u043d\u043d\u044b\u0445.<\/li>\n<\/ul>\n<p><\/p>\n<p>\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 2 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0445 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0434\u043b\u044f \u043a\u043b\u044e\u0447\u0435\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u2014 \u0445\u0430\u0440\u0434\u0432\u0435\u0440\u043d\u044b\u0435 \u043a\u043e\u0448\u0435\u043b\u044c\u043a\u0438 \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f. \u0425\u0430\u0440\u0434\u0432\u0435\u0440\u043d\u044b\u0435 \u043a\u043e\u0448\u0435\u043b\u044c\u043a\u0438 \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u0432\u043e\u0435\u043c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b, \u043e\u0434\u043d\u0430\u043a\u043e \u0441\u043b\u043e\u0436\u043d\u044b \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0438 \u0434\u0430\u043b\u0435\u043a\u043e \u043d\u0435 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b, \u0430 \u0432\u043e\u0442 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438, \u0430 \u0435\u0449\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b \u0434\u043b\u044f \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. <\/p>\n<p><\/p>\n<p>\u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f \u0432\u0441\u0435 \u044d\u0442\u043e, \u043c\u044b \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0434\u0435\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0439 API \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438 \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u044f\u043c\u0438.<br \/>\n\u041e\u0431 \u044d\u0442\u043e\u043c \u043e\u043f\u044b\u0442\u0435 \u043c\u044b \u0432\u0430\u043c \u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0435\u043c \u043d\u0438\u0436\u0435. <\/p>\n<p><\/p>\n<p><strong>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u0430\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435, \u0441 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438 \u043a\u043e\u0434\u0430 \u0438 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u0430\u043c\u0438.<\/strong> \u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0432 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/siemarell\/extension-demo\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a><\/noindex>. \u041a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043c\u043c\u0438\u0442 \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u0443 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2 id=\"kratkaya-istoriya-brauzernyh-rasshireniy\">\u041a\u0440\u0430\u0442\u043a\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439<\/h2>\n<p><\/p>\n<p>\u0411\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u0430\u0432\u043d\u043e. \u0412 Internet Explorer \u043e\u043d\u0438 \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u0435\u0449\u0435 \u0432 1999-\u043c \u0433\u043e\u0434\u0443, \u0432 Firefox \u2014 \u0432 2004-\u043c. \u0422\u0435\u043c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435, \u043e\u0447\u0435\u043d\u044c \u0434\u043e\u043b\u0433\u043e \u043d\u0435 \u0431\u044b\u043b\u043e \u0435\u0434\u0438\u043d\u043e\u0433\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430 \u0434\u043b\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439.<\/p>\n<p><\/p>\n<p>\u041c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u043e\u043d \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\u043c\u0438 \u0432 \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 Google Chrome. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0442\u043e\u0433\u0434\u0430 \u043d\u0435 \u0431\u044b\u043b\u043e, \u043d\u043e \u0438\u043c\u0435\u043d\u043d\u043e API Chrome \u0441\u0442\u0430\u043b \u0435\u0435 \u043e\u0441\u043d\u043e\u0432\u043e\u0439: \u0437\u0430\u0432\u043e\u0435\u0432\u0430\u0432 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0440\u044b\u043d\u043a\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432 \u0438 \u0438\u043c\u0435\u044f \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043c\u0430\u0433\u0430\u0437\u0438\u043d \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, Chrome \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0437\u0430\u0434\u0430\u043b \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u0434\u043b\u044f \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439.<\/p>\n<p><\/p>\n<p>\u0423 Mozilla \u0431\u044b\u043b \u0441\u0432\u043e\u0439 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442, \u043d\u043e, \u0432\u0438\u0434\u044f \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439 \u0434\u043b\u044f Chrome, \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f \u0440\u0435\u0448\u0438\u043b\u0430 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0439 API. \u0412 2015 \u0433\u043e\u0434\u0443 \u043f\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u0442\u0438\u0432\u0435 Mozilla \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 World Wide Web Consortium (W3C) \u0431\u044b\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0433\u0440\u0443\u043f\u043f\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0434 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f\u043c\u0438 \u043a\u0440\u043e\u0441\u0441\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439.<\/p>\n<p><\/p>\n<p>\u0417\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u0431\u044b\u043b \u0432\u0437\u044f\u0442 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 API \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u0421hrome. \u0420\u0430\u0431\u043e\u0442\u0430 \u0432\u0435\u043b\u0430\u0441\u044c \u043f\u0440\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 Microsoft (Google \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0430 \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u043a\u0430\u0437\u0430\u043b\u0441\u044f), \u0438 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0447\u0435\u0440\u043d\u043e\u0432\u0438\u043a <noindex><a rel=\"nofollow\" href=\"https:\/\/browserext.github.io\/browserext\/\">\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>\u0424\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 Edge, Firefox \u0438 Opera (\u0437\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u0447\u0442\u043e \u0432 \u044d\u0442\u043e\u043c \u0441\u043f\u0438\u0441\u043a\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 Chrome). \u041d\u043e \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u0432\u043e \u043c\u043d\u043e\u0433\u043e\u043c \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c \u0438 \u0441 Chrome, \u0442\u0430\u043a \u043a\u0430\u043a \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0435\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e WebExtensions API \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.mozilla.org\/WebExtensions\/FAQ#Is_the_WebExtensions_API_a_Web_standard.3F\">\u0437\u0434\u0435\u0441\u044c<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2 id=\"struktura-rasshireniya\">\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f<\/h2>\n<p><\/p>\n<p>\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u2014 \u043c\u0430\u043d\u0438\u0444\u0435\u0441\u0442 (manifest.json). \u041e\u043d \u0436\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u201c\u0442\u043e\u0447\u043a\u043e\u0439 \u0432\u0445\u043e\u0434\u0430\u201d \u0432 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435.<\/p>\n<p><\/p>\n<h3 id=\"manifest\">\u041c\u0430\u043d\u0438\u0444\u0435\u0441\u0442<\/h3>\n<p><\/p>\n<p>\u041f\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0444\u0430\u0439\u043b \u043c\u0430\u043d\u0438\u0444\u0435\u0441\u0442\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c JSON \u0444\u0430\u0439\u043b\u043e\u043c. \u041f\u043e\u043b\u043d\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0435\u0439 \u043c\u0430\u043d\u0438\u0444\u0435\u0441\u0442\u0430 \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a\u0438\u0435 \u043a\u043b\u044e\u0447\u0438 \u0432 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043a\u0430\u043a\u043e\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Mozilla\/Add-ons\/WebExtensions\/manifest.json\">\u0437\u0434\u0435\u0441\u044c<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>\u041a\u043b\u044e\u0447\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435\u0442 \u0432 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u201c\u043c\u043e\u0433\u0443\u0442\u201d \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u044b (\u0438 Chrome, \u0438 Firefox \u043f\u0438\u0448\u0443\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445, \u043d\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u044e\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c).<\/p>\n<p><\/p>\n<p>\u0410 \u044f \u0431\u044b \u0445\u043e\u0442\u0435\u043b \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b.<\/p>\n<p><\/p>\n<ol>\n<li><strong>background<\/strong> \u2014 \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u043b\u044f:\n<ol>\n<li><strong>scripts<\/strong> \u2014 \u043c\u0430\u0441\u0441\u0438\u0432 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b \u0432 background-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 (\u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e\u0431 \u044d\u0442\u043e\u043c \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435);<\/li>\n<li><strong>page<\/strong> \u2014 \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u0441\u044f \u0432 \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435, \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c html \u0441 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u043e\u043c. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u043b\u0435 script \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e, \u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u043e\u043c;<\/li>\n<li><strong>persistent<\/strong> \u2014 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0439 \u0444\u043b\u0430\u0433, e\u0441\u043b\u0438 \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d, \u0442\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 &#171;\u0443\u0431\u0438\u0432\u0430\u0442\u044c&#187; background-\u043f\u0440\u043e\u0446\u0435\u0441\u0441, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0435\u0442, \u0447\u0442\u043e \u043e\u043d \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u0442, \u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438. \u0412 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u0440\u0443\u0436\u0435\u043d\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. \u041d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 Firefox.<\/li>\n<\/ol>\n<\/li>\n<li><strong>content_scripts<\/strong> \u2014 \u043c\u0430\u0441\u0441\u0438\u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u043a \u0440\u0430\u0437\u043d\u044b\u043c \u0432\u0435\u0431 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u043c. \u041a\u0430\u0436\u0434\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0432\u0430\u0436\u043d\u044b\u0435 \u043f\u043e\u043b\u044f:\n<ol>\n<li><strong>matches<\/strong> \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Mozilla\/Add-ons\/WebExtensions\/manifest.json\/content_scripts#Matching_URL_patterns\">\u043f\u0430\u0442\u0442\u0435\u0440\u043d url<\/a><\/noindex>, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f, \u0431\u0443\u0434\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 content script \u0438\u043b\u0438 \u043d\u0435\u0442.<\/li>\n<li><strong>js<\/strong> \u2014 \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u044b \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u0430\u0442\u0447;<\/li>\n<li><strong>exclude_matches<\/strong> \u2014 \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0438\u0437 \u043f\u043e\u043b\u044f <code>match<\/code> URL, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u044e\u0442 \u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u043b\u044e.<\/li>\n<\/ol>\n<\/li>\n<li><strong>page_action<\/strong> \u2014 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0438\u043a\u043e\u043d\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0440\u044f\u0434\u043e\u043c \u0441 \u0430\u0434\u0440\u0435\u0441\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u043d\u0435\u0439. \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0442\u0430\u043a \u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c popup \u043e\u043a\u043d\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0437\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0432\u043e\u0438\u0445 HTML, CSS \u0438 JS.\n<ol>\n<li><strong>default_popup<\/strong> \u2014 \u043f\u0443\u0442\u044c \u0434\u043e HTML \u0444\u0430\u0439\u043b\u0430 \u0441 popup-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c, \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c CSS \u0438 JS.<\/li>\n<\/ol>\n<\/li>\n<li><strong>permissions<\/strong> \u2014 \u043c\u0430\u0441\u0441\u0438\u0432 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u0430\u0432\u0430\u043c\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 3 \u0442\u0438\u043f\u0430 \u043f\u0440\u0430\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u044b <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Mozilla\/Add-ons\/WebExtensions\/manifest.json\/permissions#API_permissions\">\u0442\u0443\u0442<\/a><\/noindex><\/li>\n<li><strong>web_accessible_resources<\/strong> \u2014 \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0432\u0435\u0431 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u0444\u0430\u0439\u043b\u044b JS, CSS, HTML. <\/li>\n<li><strong>externally_connectable<\/strong> \u2014 \u0437\u0434\u0435\u0441\u044c \u043c\u043e\u0436\u043d\u043e \u044f\u0432\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c ID \u0434\u0440\u0443\u0433\u0438\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439 \u0438 \u0434\u043e\u043c\u0435\u043d\u044b \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f. \u0414\u043e\u043c\u0435\u043d \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u0438 \u0432\u044b\u0448\u0435. \u041d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 Firefox.<\/li>\n<\/ol>\n<p><\/p>\n<h2 id=\"kontekst-vypolneniya\">\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f<\/h2>\n<p><\/p>\n<p>\u0423 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0435\u0441\u0442\u044c \u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430, \u0442\u043e \u0435\u0441\u0442\u044c, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0442\u0440\u0435\u0445 \u0447\u0430\u0441\u0442\u0435\u0439 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c \u0443\u0440\u043e\u0432\u043d\u0435\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a API \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430.<\/p>\n<p><\/p>\n<h3 id=\"extension-context\">Extension context<\/h3>\n<p><\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c API. \u0412 \u044d\u0442\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 &#171;\u0436\u0438\u0432\u0443\u0442&#187;:<\/p>\n<p><\/p>\n<ol>\n<li><strong>Background page<\/strong> \u2014 \u201cbackend\u201d \u0447\u0430\u0441\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f. \u0424\u0430\u0439\u043b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043c\u0430\u043d\u0438\u0444\u0435\u0441\u0442\u0435 \u043f\u043e \u043a\u043b\u044e\u0447\u0443 \u201cbackground\u201d.<\/li>\n<li><strong>Popup page<\/strong> \u2014 popup \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u0438\u043a\u043e\u043d\u043a\u0443 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f. \u0412 \u043c\u0430\u043d\u0438\u0444\u0435\u0441\u0442\u0435 <code>browser_action<\/code> -&gt; <code>default_popup<\/code>.<\/li>\n<li><strong>Custom page<\/strong> \u2014 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f, &#171;\u0436\u0438\u0432\u0443\u0449\u0430\u044f&#187; \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u0432\u0438\u0434\u0430 <code>chrome-extension:\/\/&lt;id_\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f&gt;\/customPage.html<\/code>.<\/li>\n<\/ol>\n<p><\/p>\n<p>\u042d\u0442\u043e\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u043e\u043a\u043e\u043d \u0438 \u0432\u043a\u043b\u0430\u0434\u043e\u043a \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. <strong>Background page<\/strong> \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0435 \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432\u0441\u0435\u0433\u0434\u0430 (\u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u2014 event page, \u043a\u043e\u0433\u0434\u0430 background-\u0441\u043a\u0440\u0438\u043f\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043f\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044e \u0438 &#171;\u0443\u043c\u0438\u0440\u0430\u0435\u0442&#187; \u043f\u043e\u0441\u043b\u0435 \u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f). <strong>Popup page<\/strong> \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442, \u043a\u043e\u0433\u0434\u0430 \u043e\u0442\u043a\u0440\u044b\u0442\u043e \u043e\u043a\u043d\u043e popup, \u0430 <strong>Custom page<\/strong> \u2014 \u043f\u043e\u043a\u0430 \u043e\u0442\u043a\u0440\u044b\u0442\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u0441 \u043d\u0435\u0439. \u0414\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0434\u0440\u0443\u0433\u0438\u043c \u0432\u043a\u043b\u0430\u0434\u043a\u0430\u043c \u0438 \u0438\u0445 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c\u0443 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u043d\u0435\u0442.<\/p>\n<p><\/p>\n<h3 id=\"content-script-context\">Content script context<\/h3>\n<p><\/p>\n<p>\u0424\u0430\u0439\u043b \u043a\u043e\u043d\u0442\u0435\u043d\u0442-\u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043a\u0430\u0436\u0434\u043e\u0439 \u0432\u043a\u043b\u0430\u0434\u043a\u043e\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. \u0423 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0447\u0430\u0441\u0442\u0438 API \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0438 \u043a DOM-\u0434\u0435\u0440\u0435\u0432\u0443 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b. \u0418\u043c\u0435\u043d\u043d\u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442-\u0441\u043a\u0440\u0438\u043f\u0442\u044b \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0442 \u0437\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435\u0439. \u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f, \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u0438\u0440\u0443\u044e\u0449\u0438\u0435 DOM-\u0434\u0435\u0440\u0435\u0432\u043e\u043c, \u0434\u0435\u043b\u0430\u044e\u0442 \u044d\u0442\u043e \u0432 \u043a\u043e\u043d\u0442\u0435\u043d\u0442-\u0441\u043a\u0440\u0438\u043f\u0442\u0430\u0445 \u2013 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u0438 \u0440\u0435\u043a\u043b\u0430\u043c\u044b \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0447\u0438\u043a\u0438. \u0422\u0430\u043a\u0436\u0435 \u043a\u043e\u043d\u0442\u0435\u043d\u0442-\u0441\u043a\u0440\u0438\u043f\u0442 \u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u0441\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 <code>postMessage<\/code>.<\/p>\n<p><\/p>\n<h3 id=\"web-page-context\">Web page context<\/h3>\n<p><\/p>\n<p>\u042d\u0442\u043e \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441\u0430\u043c\u0430 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430. \u041a \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044e \u043e\u043d\u0430 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044f \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0442\u0443\u0434\u0430 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442, \u043a\u0440\u043e\u043c\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432, \u043a\u043e\u0433\u0434\u0430 \u0432 \u043c\u0430\u043d\u0438\u0444\u0435\u0441\u0442\u0435 \u044f\u0432\u043d\u043e \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d \u0434\u043e\u043c\u0435\u043d \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b (\u043e\u0431 \u044d\u0442\u043e\u043c \u2014 \u043d\u0438\u0436\u0435).<\/p>\n<p><\/p>\n<h2 id=\"obmen-soobscheniyami\">\u041e\u0431\u043c\u0435\u043d \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438<\/h2>\n<p><\/p>\n<p>\u0420\u0430\u0437\u043d\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u044b \u043e\u0431\u043c\u0435\u043d\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 API <code>runtime.sendMessage<\/code> \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f <code>background<\/code> \u0438 <code>tabs.sendMessage<\/code> \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 (\u043a\u043e\u043d\u0442\u0435\u043d\u0442-\u0441\u043a\u0440\u0438\u043f\u0442\u0443, popup&#8217;\u0443 \u0438\u043b\u0438 \u0432\u0435\u0431 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 <code>externally_connectable<\/code>). \u041d\u0438\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d \u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0438 \u043a API Chrome.<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">\/\/ \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u043e\u0439 JSON \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442\nconst msg = {a: 'foo', b: 'bar'};\n\n\/\/ extensionId \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u0441\u043b\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 '\u0441\u0432\u043e\u0435\u043c\u0443' \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044e (\u0438\u0437 ui \u0438\u043b\u0438 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0441\u043a\u0440\u0438\u043f\u0442\u0430)\nchrome.runtime.sendMessage(extensionId, msg);\n\n\/\/ \u0422\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\nchrome.runtime.onMessage.addListener((msg) =&gt; console.log(msg))\n\n\/\/ \u041c\u043e\u0436\u043d\u043e \u0441\u043b\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432\u043a\u043b\u0430\u0434\u043a\u0430\u043c \u0437\u043d\u0430\u044f \u0438\u0445 id\nchrome.tabs.sendMessage(tabId, msg)\n\n\/\/ \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a \u0432\u043a\u043b\u0430\u0434\u043a\u0430\u043c \u0438 \u0438\u0445 id \u043c\u043e\u0436\u043d\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u043e\u0442 \u0442\u0430\u043a\nchrome.tabs.query(\n    {currentWindow: true, active : true},\n    function(tabArray){\n      tabArray.forEach(tab =&gt; console.log(tab.id))\n    }\n)<\/code><\/pre>\n<p><\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 <code>runtime.connect<\/code>. \u0412 \u043e\u0442\u0432\u0435\u0442 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c <code>runtime.Port<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439, \u043f\u043e\u043a\u0430 \u043e\u043d \u043e\u0442\u043a\u0440\u044b\u0442, \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043b\u044e\u0431\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u041d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>contentscript<\/code>, \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">\/\/ \u041e\u043f\u044f\u0442\u044c \u0436\u0435 extensionId \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u043c\u0435\u043d\u043e\u0432\u0430\u0442\u044c\nconst port = chrome.runtime.connect({name: \"knockknock\"});\nport.postMessage({joke: \"Knock knock\"});\nport.onMessage.addListener(function(msg) {\n    if (msg.question === \"Who's there?\")\n        port.postMessage({answer: \"Madame\"});\n    else if (msg.question === \"Madame who?\")\n        port.postMessage({answer: \"Madame... Bovary\"});\n<\/code><\/pre>\n<p><\/p>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440 \u0438\u043b\u0438 background:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">\/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f '\u0441\u0432\u043e\u0438\u0445' \u0432\u043a\u043b\u0430\u0434\u043e\u043a. \u041a\u043e\u043d\u0442\u0435\u043d\u0442 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432, popup \u0438\u043b\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\nchrome.runtime.onConnect.addListener(function(port) {\n    console.assert(port.name === \"knockknock\");\n    port.onMessage.addListener(function(msg) {\n        if (msg.joke === \"Knock knock\")\n            port.postMessage({question: \"Who's there?\"});\n        else if (msg.answer === \"Madame\")\n            port.postMessage({question: \"Madame who?\"});\n        else if (msg.answer === \"Madame... Bovary\")\n            port.postMessage({question: \"I don't get it.\"});\n    });\n});\n\n\/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0432\u043a\u043b\u0430\u0434\u043e\u043a. \u0414\u0440\u0443\u0433\u0438\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439 \u0438\u043b\u0438 \u0432\u0435\u0431 \u0441\u0442\u0440\u0430\u043d\u0438\u0446, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f \u0432 \u043c\u0430\u043d\u0438\u0444\u0435\u0441\u0442\u0435\nchrome.runtime.onConnectExternal.addListener(function(port) {\n    ...\n});<\/code><\/pre>\n<p><\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0435\u0441\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 <code>onDisconnect<\/code> \u0438 \u043c\u0435\u0442\u043e\u0434 <code>disconnect<\/code>.<\/p>\n<p><\/p>\n<h2 id=\"shema-prilozheniya\">\u0421\u0445\u0435\u043c\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h2>\n<p><\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u0442 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435 \u043a\u043b\u044e\u0447\u0438, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 (\u0430\u0434\u0440\u0435\u0441, \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u043e\u0431\u0449\u0430\u0435\u0442\u0441\u044f \u0441\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435\u0439 \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u043f\u043e\u0434\u043f\u0438\u0441\u044c \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439.<\/p>\n<p><\/p>\n<h2 id=\"razrabotka-prilozheniya\">\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h2>\n<p><\/p>\n<p>\u041d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u043a\u0430\u043a \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c, \u0442\u0430\u043a \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 API \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439). \u041e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u043e\u0434\u043d\u0438\u043c \u043b\u0438\u0448\u044c <code>contentscript<\/code> \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u0443 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0442\u043e\u043b\u044c\u043a\u043e \u043a DOM, \u043d\u043e \u043d\u0435 \u043a JS \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <code>runtime.connect<\/code> \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e API \u043d\u0443\u0436\u0435\u043d \u043d\u0430 \u0432\u0441\u0435\u0445 \u0434\u043e\u043c\u0435\u043d\u0430\u0445, \u0430 \u0432 \u043c\u0430\u043d\u0438\u0444\u0435\u0441\u0442\u0435 \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435. \u0412 \u0438\u0442\u043e\u0433\u0435 \u0441\u0445\u0435\u043c\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/30f08b2c1d0362d51b057b51ff1ef6d1.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u0411\u0443\u0434\u0435\u0442 \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0441\u043a\u0440\u0438\u043f\u0442 \u2014 <code>inpage<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u043d\u0436\u0435\u043a\u0442\u0438\u0442\u044c \u0432 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u0435\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c API \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c.<\/p>\n<p><\/p>\n<h3 id=\"nachalo\">\u041d\u0430\u0447\u0430\u043b\u043e<\/h3>\n<p><\/p>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/siemarell\/extension-demo\/tree\/transactions\">GitHub<\/a><\/noindex>. \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043a\u043e\u043c\u043c\u0438\u0442\u044b.<\/p>\n<p><\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043c\u0430\u043d\u0438\u0444\u0435\u0441\u0442\u0430:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">{\n  \/\/ \u0418\u043c\u044f \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435, \u0432\u0435\u0440\u0441\u0438\u044f. \u0412\u0441\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u0438\u0434\u043d\u043e \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u0432 chrome:\/\/extensions\/?id=&lt;id \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f&gt;\n  \"name\": \"Signer\",\n  \"description\": \"Extension demo\",\n  \"version\": \"0.0.1\",\n  \"manifest_version\": 2,\n\n  \/\/ \u0421\u043a\u0440\u0438\u043f\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0442\u0441\u044f \u0432 background, \u0438\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e\n  \"background\": {\n    \"scripts\": [\"background.js\"]\n  },\n\n  \/\/ \u041a\u0430\u043a\u043e\u0439 html \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f popup\n  \"browser_action\": {\n    \"default_title\": \"My Extension\",\n    \"default_popup\": \"popup.html\"\n  },\n\n  \/\/ \u041a\u043e\u043d\u0442\u0435\u043d\u0442 \u0441\u043a\u0440\u0438\u043f\u0442\u044b.\n  \/\/ \u0423 \u043d\u0430\u0441 \u043e\u0434\u0438\u043d \u043e\u0431\u044a\u0435\u043a\u0442: \u0434\u043b\u044f \u0432\u0441\u0435\u0445 url \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445\u0441\u044f \u0441 http \u0438\u043b\u0438 https \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c\n  \/\/ contenscript context \u0441\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c contentscript.js. \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0441\u0440\u0430\u0437\u0443 \u043f\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0444\u0440\u0435\u0439\u043c\u043e\u0432\n  \"content_scripts\": [\n    {\n      \"matches\": [\n        \"http:\/\/*\/*\",\n        \"https:\/\/*\/*\"\n      ],\n      \"js\": [\n        \"contentscript.js\"\n      ],\n      \"run_at\": \"document_start\",\n      \"all_frames\": true\n    }\n  ],\n  \/\/ \u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f \u043a localStorage \u0438 idle api\n  \"permissions\": [\n    \"storage\",\n    \/\/ \"unlimitedStorage\",\n    \/\/\"clipboardWrite\",\n    \"idle\"\n    \/\/\"activeTab\",\n    \/\/\"webRequest\",\n    \/\/\"notifications\",\n    \/\/\"tabs\"\n  ],\n  \/\/ \u0417\u0434\u0435\u0441\u044c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0432\u0435\u0431 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430. \u0422\u043e\u0435\u0441\u0442\u044c \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c fetche'\u043c \u0438\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e xhr\n  \"web_accessible_resources\": [\"inpage.js\"]\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0443\u0441\u0442\u044b\u0435 background.js, popup.js, inpage.js \u0438 contentscript.js. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c popup.html \u2014 \u0438 \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0443\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0432 Google Chrome \u0438 \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043e\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<p><\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u044d\u0442\u043e\u043c, \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u043a\u043e\u0434 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/siemarell\/extension-demo\/tree\/manifest-app-template\">\u043e\u0442\u0441\u044e\u0434\u0430<\/a><\/noindex>. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438, \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0441\u0431\u043e\u0440\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e webpack. \u0427\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440, \u0432 chrome:\/\/extensions \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c load unpacked \u0438 \u043f\u0430\u043f\u043a\u0443 \u0441 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c \u2014 \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 dist.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/b1b51fe4b0d2dcfe78c65940e0a38c83.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p><\/p>\n<p>popup -&gt;<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/d7d3f8d49cd05b034defe7059a3480aa.jpeg\" style=\"display:block;margin: 0 auto;\" \/> <\/p>\n<p><\/p>\n<p>\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u043a\u043e\u043d\u0442\u0435\u043d\u0442-\u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0441\u0430\u043c\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u043d \u0437\u0430\u043f\u0443\u0449\u0435\u043d.<img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/d4875b4c348fa49da2123f21a2f93189.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>\u041e\u0431\u043c\u0435\u043d \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438<\/strong><\/p>\n<p><\/p>\n<p>\u0418\u0442\u0430\u043a, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u0432\u0430 \u043a\u0430\u043d\u0430\u043b\u0430 \u0441\u0432\u044f\u0437\u0438: inpage &lt;-&gt; background \u0438 popup &lt;-&gt; background. \u041c\u043e\u0436\u043d\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u043f\u043e\u0440\u0442 \u0438 \u0438\u0437\u043e\u0431\u0440\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u0439 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b, \u043d\u043e \u043c\u043d\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u043f\u043e\u0434\u0445\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u043f\u043e\u0434\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u043a\u043e\u0434\u043e\u043c metamask.<\/p>\n<p><\/p>\n<p>\u042d\u0442\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u0435\u0442\u044c\u044e Ethereum. \u0412 \u043d\u0435\u043c \u0440\u0430\u0437\u043d\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0430\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 RPC \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 dnode. \u041e\u043d\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u0438 \u0443\u0434\u043e\u0431\u043d\u043e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u043c\u0435\u043d, \u0435\u0441\u043b\u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0430 \u0435\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c nodejs stream (\u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0443 \u043e\u0431\u044a\u0435\u043a\u0442, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0438\u0439 \u0442\u043e\u0442 \u0436\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441): <\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import Dnode from \"dnode\/browser\";\n\n\/\/ \u0412 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u043c\u0441\u044f \u0447\u0442\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0445\u043e\u0442\u044f \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0430\u043c \u043d\u0435 \u043c\u0435\u0448\u0430\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0434\u0432\u0443\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u043c\n\n\/\/ C\u0435\u0440\u0432\u0435\u0440\n\/\/ API, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c\nconst dnode = Dnode({\n    hello: (cb) =&gt; cb(null, \"world\")\n})\n\/\/ \u0422\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442, \u043f\u043e\u0432\u0435\u0440\u0445 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c dnode. \u041b\u044e\u0431\u043e\u0439 nodejs \u0441\u0442\u0440\u0438\u043c. \u0412 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u0435\u0441\u0442\u044c \u0431\u0438\u0431\u0438\u043b\u0438\u043e\u0442\u0435\u043a\u0430 'readable-stream'\nconnectionStream.pipe(dnode).pipe(connectionStream)\n\n\/\/ \u041a\u043b\u0438\u0435\u043d\u0442\nconst dnodeClient = Dnode() \/\/ \u0412\u044b\u0437\u043e\u0432 \u0431\u0435\u0437 \u0430\u0433\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0437\u043d\u0430\u0447\u0438\u0442 \u0447\u0442\u043e \u043c\u044b \u043d\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c API \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u0435\n\n\/\/ \u0412\u044b\u0432\u0435\u0434\u0435\u0442 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c world\ndnodeClient.once('remote', remote =&gt; {\n    remote.hello(((err, value) =&gt; console.log(value)))\n})<\/code><\/pre>\n<p><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041e\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u044b API \u0434\u043b\u044f popup \u0438 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c dnode \u0434\u043b\u044f \u043d\u0438\u0445:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import Dnode from 'dnode\/browser';\n\nexport class SignerApp {\n\n    \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 API \u0434\u043b\u044f ui\n    popupApi(){\n        return {\n            hello: cb =&gt; cb(null, 'world')\n        }\n    }\n\n    \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u0442 API \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b\n    pageApi(){\n        return {\n            hello: cb =&gt; cb(null, 'world')\n        }\n    }\n\n    \/\/ \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 popup ui\n    connectPopup(connectionStream){\n        const api = this.popupApi();\n        const dnode = Dnode(api);\n\n        connectionStream.pipe(dnode).pipe(connectionStream);\n\n        dnode.on('remote', (remote) =&gt; {\n            console.log(remote)\n        })\n    }\n\n    \/\/ \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443\n    connectPage(connectionStream, origin){\n        const api = this.popupApi();\n        const dnode = Dnode(api);\n\n        connectionStream.pipe(dnode).pipe(connectionStream);\n\n        dnode.on('remote', (remote) =&gt; {\n            console.log(origin);\n            console.log(remote)\n        })\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u0438 \u0434\u0430\u043b\u0435\u0435 \u0432\u043c\u0435\u0441\u0442\u043e \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 Chrome \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c extentionApi, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043a Chrome \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043e\u0442 Google \u0438 \u043a browser \u0432 \u0434\u0440\u0443\u0433\u0438\u0445. \u0414\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u044d\u0442\u043e \u0434\u043b\u044f \u043a\u0440\u043e\u0441\u0441\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0441\u0442\u0438, \u043d\u043e \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u2018chrome.runtime.connect\u2019.<\/p>\n<p><\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 background \u0441\u043a\u0440\u0438\u043f\u0442\u0435:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {extensionApi} from \".\/utils\/extensionApi\";\nimport {PortStream} from \".\/utils\/PortStream\";\nimport {SignerApp} from \".\/SignerApp\";\n\nconst app = new SignerApp();\n\n\/\/ onConnect \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 '\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432' (contentscript, popup, \u0438\u043b\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f)\nextensionApi.runtime.onConnect.addListener(connectRemote);\n\nfunction connectRemote(remotePort) {\n    const processName = remotePort.name;\n    const portStream = new PortStream(remotePort);\n    \/\/ \u041f\u0440\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u043c\u044f, \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u0438\u043c\u0435\u043d\u0438 \u043c\u044b \u0438 \u043e\u043f\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043a\u0442\u043e \u043a \u043d\u0430\u043c \u043f\u043e\u0434\u043b\u044e\u0447\u0438\u043b\u0441\u044f, \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0441\u043a\u0440\u0438\u043f\u0442 \u0438\u043b\u0438 ui\n    if (processName === 'contentscript'){\n        const origin = remotePort.sender.url\n        app.connectPage(portStream, origin)\n    }else{\n        app.connectPopup(portStream)\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a dnode \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441\u043e \u0441\u0442\u0440\u0438\u043c\u0430\u043c\u0438, \u0430 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u043e\u0440\u0442, \u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441-\u0430\u0434\u0430\u043f\u0442\u0435\u0440. \u041e\u043d \u0441\u0434\u0435\u043b\u0430\u043d \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 readable-stream, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 nodejs-\u0441\u0442\u0440\u0438\u043c\u044b \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {Duplex} from 'readable-stream';\n\nexport class PortStream extends Duplex{\n    constructor(port){\n        super({objectMode: true});\n        this._port = port;\n        port.onMessage.addListener(this._onMessage.bind(this));\n        port.onDisconnect.addListener(this._onDisconnect.bind(this))\n    }\n\n    _onMessage(msg) {\n        if (Buffer.isBuffer(msg)) {\n            delete msg._isBuffer;\n            const data = new Buffer(msg);\n            this.push(data)\n        } else {\n            this.push(msg)\n        }\n    }\n\n    _onDisconnect() {\n        this.destroy()\n    }\n\n    _read(){}\n\n    _write(msg, encoding, cb) {\n        try {\n            if (Buffer.isBuffer(msg)) {\n                const data = msg.toJSON();\n                data._isBuffer = true;\n                this._port.postMessage(data)\n            } else {\n                this._port.postMessage(msg)\n            }\n        } catch (err) {\n            return cb(new Error('PortStream - disconnected'))\n        }\n        cb()\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0432 UI:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {extensionApi} from \".\/utils\/extensionApi\";\nimport {PortStream} from \".\/utils\/PortStream\";\nimport Dnode from 'dnode\/browser';\n\nconst DEV_MODE = process.env.NODE_ENV !== 'production';\n\nsetupUi().catch(console.error);\n\nasync function setupUi(){\n    \/\/ \u0422\u0430\u043a\u0436\u0435, \u043a\u0430\u043a \u0438 \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u043e\u0440\u0442, \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u043c \u0432 stream, \u0434\u0435\u043b\u0430\u0435\u043c  dnode\n    const backgroundPort = extensionApi.runtime.connect({name: 'popup'});\n    const connectionStream = new PortStream(backgroundPort);\n\n    const dnode = Dnode();\n\n    connectionStream.pipe(dnode).pipe(connectionStream);\n\n    const background = await new Promise(resolve =&gt; {\n        dnode.once('remote', api =&gt; {\n            resolve(api)\n        })\n    });\n\n    \/\/ \u0414\u0435\u043b\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 API \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c \u0438\u0437 \u043a\u043e\u043d\u0441\u043e\u043b\u0438\n    if (DEV_MODE){\n        global.background = background;\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0432 content script:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {extensionApi} from \".\/utils\/extensionApi\";\nimport {PortStream} from \".\/utils\/PortStream\";\nimport PostMessageStream from 'post-message-stream';\n\nsetupConnection();\ninjectScript();\n\nfunction setupConnection(){\n    const backgroundPort = extensionApi.runtime.connect({name: 'contentscript'});\n    const backgroundStream = new PortStream(backgroundPort);\n\n    const pageStream = new PostMessageStream({\n        name: 'content',\n        target: 'page',\n    });\n\n    pageStream.pipe(backgroundStream).pipe(pageStream);\n}\n\nfunction injectScript(){\n    try {\n        \/\/ inject in-page script\n        let script = document.createElement('script');\n        script.src = extensionApi.extension.getURL('inpage.js');\n        const container = document.head || document.documentElement;\n        container.insertBefore(script, container.children[0]);\n        script.onload = () =&gt; script.remove();\n    } catch (e) {\n        console.error('Injection failed.', e);\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a API \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043d\u0435 \u0432 \u043a\u043e\u043d\u0442\u0435\u043d\u0442-\u0441\u043a\u0440\u0438\u043f\u0442\u0435, \u0430 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435, \u043c\u044b \u0434\u0435\u043b\u0430\u0435\u043c \u0434\u0432\u0435 \u0432\u0435\u0449\u0438:<\/p>\n<p><\/p>\n<ol>\n<li>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0434\u0432\u0430 \u0441\u0442\u0440\u0438\u043c\u0430. \u041e\u0434\u0438\u043d \u2014 \u0432 \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u043f\u043e\u0432\u0435\u0440\u0445 postMessage. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432\u043e\u0442 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.npmjs.com\/package\/post-message-stream\">\u044d\u0442\u043e\u0442 \u043f\u0430\u043a\u0435\u0442<\/a><\/noindex> \u043e\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u0439 metamask. \u0412\u0442\u043e\u0440\u043e\u0439 \u0441\u0442\u0440\u0438\u043c \u2014 \u043a background \u043f\u043e\u0432\u0435\u0440\u0445 \u043f\u043e\u0440\u0442\u0430, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u0442 <code>runtime.connect<\/code>. \u041f\u0430\u0439\u043f\u0438\u043c \u0438\u0445. \u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0440\u0438\u043c \u0434\u043e \u0431\u044d\u043a\u0433\u0440\u0430\u0443\u043d\u0434\u0430.<\/li>\n<li>\u0418\u043d\u0436\u0435\u043a\u0442\u0438\u043c \u0441\u043a\u0440\u0438\u043f\u0442 \u0432 DOM. \u0412\u044b\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442 (\u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0435\u043c\u0443 \u0431\u044b\u043b \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d \u0432 \u043c\u0430\u043d\u0438\u0444\u0435\u0441\u0442\u0435) \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0435\u0433 <code>script<\/code> \u0441 \u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c \u0432\u043d\u0443\u0442\u0440\u0438:<\/li>\n<\/ol>\n<p><\/p>\n<pre><code class=\"javascript\">import PostMessageStream from 'post-message-stream';\nimport {extensionApi} from \".\/utils\/extensionApi\";\nimport {PortStream} from \".\/utils\/PortStream\";\n\nsetupConnection();\ninjectScript();\n\nfunction setupConnection(){\n    \/\/ \u0421\u0442\u0440\u0438\u043c \u043a \u0431\u0435\u043a\u0433\u0440\u0430\u0443\u043d\u0434\u0443\n    const backgroundPort = extensionApi.runtime.connect({name: 'contentscript'});\n    const backgroundStream = new PortStream(backgroundPort);\n\n    \/\/ \u0421\u0442\u0440\u0438\u043c \u043a \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435\n    const pageStream = new PostMessageStream({\n        name: 'content',\n        target: 'page',\n    });\n\n    pageStream.pipe(backgroundStream).pipe(pageStream);\n}\n\nfunction injectScript(){\n    try {\n        \/\/ inject in-page script\n        let script = document.createElement('script');\n        script.src = extensionApi.extension.getURL('inpage.js');\n        const container = document.head || document.documentElement;\n        container.insertBefore(script, container.children[0]);\n        script.onload = () =&gt; script.remove();\n    } catch (e) {\n        console.error('Injection failed.', e);\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 api \u0432 inpage \u0438 \u0437\u0430\u0432\u043e\u0434\u0438\u043c \u0435\u0433\u043e global:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import PostMessageStream from 'post-message-stream';\nimport Dnode from 'dnode\/browser';\n\nsetupInpageApi().catch(console.error);\n\nasync function setupInpageApi() {\n    \/\/ \u0421\u0442\u0440\u0438\u043c \u043a \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0441\u043a\u0440\u0438\u043f\u0442\u0443\n    const connectionStream = new PostMessageStream({\n        name: 'page',\n        target: 'content',\n    });\n\n    const dnode = Dnode();\n\n    connectionStream.pipe(dnode).pipe(connectionStream);\n\n    \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 API\n    const pageApi = await new Promise(resolve =&gt; {\n        dnode.once('remote', api =&gt; {\n            resolve(api)\n        })\n    });\n\n    \/\/ \u0414\u043e\u0441\u0442\u0443\u043f \u0447\u0435\u0440\u0435\u0437 window\n    global.SignerApp = pageApi;\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0423 \u043d\u0430\u0441 \u0433\u043e\u0442\u043e\u0432 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/siemarell\/extension-demo\/tree\/dnode-setup-callback\">Remote Procedure Call (RPC) \u0441 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c API \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0438 UI<\/a><\/noindex>. \u041f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043a background \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u044d\u0442\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/69675ed20de7d4ce68cc26e05f10683e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u041f\u0443\u0441\u0442\u043e\u0439 API \u0438 origin. \u041d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e hello \u0432\u043e\u0442 \u0442\u0430\u043a: <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/d6cad5ccecfd3b4c7035d9f58ba250fc.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 callback-\u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u0432 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u043c JS \u2014 \u043c\u043e\u0432\u0435\u0442\u043e\u043d, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0445\u0435\u043b\u043f\u0435\u0440 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f dnode, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 API \u0432 utils.<\/p>\n<p><\/p>\n<p>\u041e\u0431\u044a\u0435\u043a\u0442\u044b API \u0442\u0435\u043f\u0435\u0440\u044c \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">export class SignerApp {\n\n    popupApi() {\n        return {\n            hello: async () =&gt; \"world\"\n        }\n    }\n\n...\n\n}<\/code><\/pre>\n<p><\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043e\u0442 remote \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {cbToPromise, transformMethods} from \"..\/..\/src\/utils\/setupDnode\";\n\nconst pageApi = await new Promise(resolve =&gt; {\n    dnode.once('remote', remoteApi =&gt; {\n        \/\/ \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0443\u0442\u0438\u043b\u0438\u0442 \u043c\u0435\u043d\u044f\u0435\u043c \u0432\u0441\u0435 callback \u043d\u0430 promise\n        resolve(transformMethods(cbToPromise, remoteApi))\n    })\n});<\/code><\/pre>\n<p><\/p>\n<p>\u0410 \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0440\u043e\u043c\u0438\u0441:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/b2be1836aa03996f5b1a4dc46db06ebb.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u0412\u0435\u0440\u0441\u0438\u044f \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/siemarell\/extension-demo\/tree\/dnode-setup-async\">\u0437\u0434\u0435\u0441\u044c<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>\u0412 \u0446\u0435\u043b\u043e\u043c, \u043f\u043e\u0434\u0445\u043e\u0434 \u0441 RPC \u0438 \u0441\u0442\u0440\u0438\u043c\u0430\u043c\u0438 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0433\u0438\u0431\u043a\u0438\u043c: \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c steam multiplexing \u0438 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u043d\u044b\u0445 API \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447. \u0412 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435, dnode \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0433\u0434\u0435 \u0443\u0433\u043e\u0434\u043d\u043e, \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u2014 \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442 \u0432 \u0432\u0438\u0434\u0435 nodejs \u0441\u0442\u0440\u0438\u043c\u0430.<\/p>\n<p><\/p>\n<p>\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043e\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u0430\u0442 JSON, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b JSON RPC 2. \u041e\u0434\u043d\u0430\u043a\u043e \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c\u0438 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0430\u043c\u0438 (TCP \u0438 HTTP(S)), \u0447\u0442\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u043e.<\/p>\n<p><\/p>\n<h3 id=\"vnutrenniy-steyt-i-localstorage\">\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0441\u0442\u0435\u0439\u0442 \u0438 localStorage<\/h3>\n<p><\/p>\n<p>\u041d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0441\u0442\u0435\u0439\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u2014 \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c, \u043a\u043b\u044e\u0447\u0438 \u0434\u043b\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u0438. \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0435\u0439\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0435\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 popup API:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {setupDnode} from \".\/utils\/setupDnode\";\n\nexport class SignerApp {\n\n    constructor(){\n        this.store = {\n            keys: [],\n        };\n    }\n\n    addKey(key){\n        this.store.keys.push(key)\n    }\n\n    removeKey(index){\n        this.store.keys.splice(index,1)\n    }\n\n    popupApi(){\n        return {\n            addKey: async (key) =&gt; this.addKey(key),\n            removeKey: async (index) =&gt; this.removeKey(index)\n        }\n    }\n\n    ...\n\n} <\/code><\/pre>\n<p><\/p>\n<p>\u0412 background \u043e\u0431\u0435\u0440\u043d\u0435\u043c \u0432\u0441\u0435 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0438 \u0437\u0430\u043f\u0438\u0448\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 window, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0441 \u043d\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438\u0437 \u043a\u043e\u043d\u0441\u043e\u043b\u0438:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {extensionApi} from \".\/utils\/extensionApi\";\nimport {PortStream} from \".\/utils\/PortStream\";\nimport {SignerApp} from \".\/SignerApp\";\n\nconst DEV_MODE = process.env.NODE_ENV !== 'production';\n\nsetupApp();\n\nfunction setupApp() {\n    const app = new SignerApp();\n\n    if (DEV_MODE) {\n        global.app = app;\n    }\n\n    extensionApi.runtime.onConnect.addListener(connectRemote);\n\n    function connectRemote(remotePort) {\n        const processName = remotePort.name;\n        const portStream = new PortStream(remotePort);\n        if (processName === 'contentscript') {\n            const origin = remotePort.sender.url;\n            app.connectPage(portStream, origin)\n        } else {\n            app.connectPopup(portStream)\n        }\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0438\u0437 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 UI \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u044e\u0447\u0435\u0439 \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0441\u043e \u0441\u0442\u0435\u0439\u0442\u043e\u043c:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/5688def98b490a0a8cfa4e090aa3d489.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u0421\u0442\u0435\u0439\u0442 \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0435\u0440\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043a\u043b\u044e\u0447\u0438 \u043d\u0435 \u0442\u0435\u0440\u044f\u043b\u0438\u0441\u044c.<\/p>\n<p><\/p>\n<p>\u0425\u0440\u0430\u043d\u0438\u0442\u044c \u0431\u0443\u0434\u0435\u043c \u0432 localStorage, \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438. \u0412\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0438 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0435\u043c\u0443 \u0442\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f UI, \u0438 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f. \u0418\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u0443\u0434\u043e\u0431\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 (observable storage) \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0435\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.<\/p>\n<p><\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0443\u0434\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 mobx (<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/mobxjs\/mobx\">https:\/\/github.com\/mobxjs\/mobx<\/a><\/noindex>). \u0412\u044b\u0431\u043e\u0440 \u043f\u0430\u043b \u043d\u0430 \u043d\u0435\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043d\u0435\u0439 \u043d\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c, \u0430 \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0435\u0435 \u0438\u0437\u0443\u0447\u0438\u0442\u044c.<\/p>\n<p><\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u0442\u0435\u0439\u0442\u0430 \u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u043c store observable:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {observable, action} from 'mobx';\nimport {setupDnode} from \".\/utils\/setupDnode\";\n\nexport class SignerApp {\n\n    constructor(initState = {}) {\n        \/\/ \u0412\u043d\u0435\u0448\u043d\u0435 store \u0442\u0430\u043a \u0438 \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u0442\u0435\u043c \u0436\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c, \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0435\u0433\u043e \u043f\u043e\u043b\u044f \u0441\u0442\u0430\u043b\u0438 proxy, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u044e\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0438\u043c\n        this.store =  observable.object({\n            keys: initState.keys || [],\n        });\n    }\n\n    \/\/ \u041c\u0435\u0442\u043e\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u0435\u043d\u044f\u044e\u0442 observable \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u043e\u043c\n    @action\n    addKey(key) {\n        this.store.keys.push(key)\n    }\n\n    @action\n    removeKey(index) {\n        this.store.keys.splice(index, 1)\n    }\n\n    ...\n\n}<\/code><\/pre>\n<p><\/p>\n<p>&#171;\u041f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c&#187; mobx \u0437\u0430\u043c\u0435\u043d\u0438\u043b \u0432\u0441\u0435 \u043f\u043e\u043b\u044f store \u043d\u0430 proxy \u0438 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u0435 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a \u043d\u0438\u043c. \u041d\u0430 \u044d\u0442\u0438 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f.<\/p>\n<p><\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u044f \u0431\u0443\u0434\u0443 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u0440\u043c\u0438\u043d \u201c\u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438\u201d, \u0445\u043e\u0442\u044f \u044d\u0442\u043e \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e. Mobx \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u0438\u043c\u0435\u043d\u043d\u043e \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u043e\u043b\u044f\u043c. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0433\u0435\u0442\u0442\u0435\u0440\u044b \u0438 \u0441\u0435\u0442\u0442\u0435\u0440\u044b \u043f\u0440\u043e\u043a\u0441\u0438-\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430.<\/p>\n<p><\/p>\n<p>\u0414\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u044b action \u0441\u043b\u0443\u0436\u0430\u0442 \u0434\u0432\u0443\u043c \u0446\u0435\u043b\u044f\u043c: <\/p>\n<p><\/p>\n<ol>\n<li>\u0412 \u0441\u0442\u0440\u043e\u0433\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u0441 \u0444\u043b\u0430\u0433\u043e\u043c enforceActions mobx \u0437\u0430\u043f\u0440\u0435\u0449\u0430\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c \u0441\u0442\u0435\u0439\u0442 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e. \u0425\u043e\u0440\u043e\u0448\u0438\u043c \u0442\u043e\u043d\u043e\u043c \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0432 \u0441\u0442\u0440\u043e\u0433\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435.<\/li>\n<li>\u0414\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043c\u0435\u043d\u044f\u0435\u0442 \u0441\u0442\u0435\u0439\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u2013 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u044b \u043c\u0435\u043d\u044f\u0435\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0439 \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430, \u2014 \u043e\u0431\u0441\u0435\u0440\u0432\u0435\u0440\u044b \u043e\u043f\u043e\u0432\u0435\u0449\u0430\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u0435\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438. \u042d\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0432\u0430\u0436\u043d\u043e \u0434\u043b\u044f \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430, \u0433\u0434\u0435 \u043b\u0438\u0448\u043d\u0438\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0435\u0439\u0442\u0430 \u043f\u0440\u0438\u0432\u043e\u0434\u044f\u0442 \u043a \u043d\u0435\u043d\u0443\u0436\u043d\u043e\u043c\u0443 \u0440\u0435\u043d\u0434\u0435\u0440\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0438 \u043f\u0435\u0440\u0432\u043e\u0435, \u043d\u0438 \u0432\u0442\u043e\u0440\u043e\u0435 \u043e\u0441\u043e\u0431\u043e \u043d\u0435 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e, \u043e\u0434\u043d\u0430\u043a\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u043b\u0443\u0447\u0448\u0438\u043c \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430\u043c. \u0414\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u044b \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0432\u0435\u0448\u0430\u0442\u044c \u043d\u0430 \u0432\u0441\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u0442\u0435\u0439\u0442 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u044b\u0445 \u043f\u043e\u043b\u0435\u0439.<\/li>\n<\/ol>\n<p><\/p>\n<p>\u0412 background \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u0442\u0435\u0439\u0442\u0430 \u0432 localStorage:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {reaction, toJS} from 'mobx';\nimport {extensionApi} from \".\/utils\/extensionApi\";\nimport {PortStream} from \".\/utils\/PortStream\";\nimport {SignerApp} from \".\/SignerApp\";\n\/\/ \u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b. \u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\/\u0447\u0438\u0442\u0430\u044e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0432\/\u0438\u0437 localStorage \u0432\u0438\u0434\u0435 JSON \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u043e \u043a\u043b\u044e\u0447\u0443 'store'\nimport {loadState, saveState} from \".\/utils\/localStorage\";\n\nconst DEV_MODE = process.env.NODE_ENV !== 'production';\n\nsetupApp();\n\nfunction setupApp() {\n    const initState = loadState();\n    const app = new SignerApp(initState);\n\n    if (DEV_MODE) {\n        global.app = app;\n    }\n\n    \/\/ Setup state persistence\n\n    \/\/ \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 reaction \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c. \u041d\u0430\u043c \u044d\u0442\u043e \u043d\u0435 \u043d\u0443\u0436\u043d\u043e, \u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430\n    const localStorageReaction = reaction(\n        () =&gt; toJS(app.store), \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f-\u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445\n        saveState \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d\u0430 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\n    );\n\n    extensionApi.runtime.onConnect.addListener(connectRemote);\n\n    function connectRemote(remotePort) {\n        const processName = remotePort.name;\n        const portStream = new PortStream(remotePort);\n        if (processName === 'contentscript') {\n            const origin = remotePort.sender.url\n            app.connectPage(portStream, origin)\n        } else {\n            app.connectPopup(portStream)\n        }\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430 \u0437\u0434\u0435\u0441\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f reaction. \u0423 \u043d\u0435\u0435 \u0434\u0432\u0430 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430:<\/p>\n<p><\/p>\n<ol>\n<li>\u0421\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445.<\/li>\n<li>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u0441 \u044d\u0442\u0438\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d\u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f.<\/li>\n<\/ol>\n<p><\/p>\n<p>\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 redux, \u0433\u0434\u0435 \u043c\u044b \u044f\u0432\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0442\u0435\u0439\u0442 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430, mobx \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0442 \u043a \u043a\u0430\u043a\u0438\u043c \u0438\u043c\u0435\u043d\u043d\u043e observable \u043c\u044b \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u0430, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u0438\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a.<\/p>\n<p><\/p>\n<p>\u0412\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e mobx \u0440\u0435\u0448\u0430\u0435\u0442, \u043d\u0430 \u043a\u0430\u043a\u0438\u0435 observable \u043c\u044b \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f. \u0415\u0441\u043b\u0438 \u0431\u044b \u0432 \u043a\u043e\u0434\u0435 \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u0432\u043e\u0442 \u0442\u0430\u043a<code>() =&gt; app.store<\/code>, \u0442\u043e reaction \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u043d\u0438\u043a\u043e\u0433\u0434\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u0430\u043c \u043f\u043e \u0441\u0435\u0431\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u044b\u043c, \u0442\u0430\u043a\u043e\u0432\u044b\u043c\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0433\u043e \u043f\u043e\u043b\u044f.<\/p>\n<p><\/p>\n<p>\u0415\u0441\u043b\u0438 \u0431\u044b \u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0432\u043e\u0442 \u0442\u0430\u043a <code>() =&gt; app.store.keys<\/code>, \u0442\u043e \u043e\u043f\u044f\u0442\u044c \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e \u0431\u044b, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438\/\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043d\u0435\u0433\u043e \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u0442.<\/p>\n<p><\/p>\n<p>Mobx \u0432 \u043f\u0435\u0440\u0432\u044b\u0439 \u0440\u0430\u0437 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u0430 \u0438 \u0441\u043b\u0435\u0434\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430 \u0442\u0435\u043c\u0438 observable, \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u0438 \u0434\u043e\u0441\u0442\u0443\u043f. \u0421\u0434\u0435\u043b\u0430\u043d\u043e \u044d\u0442\u043e \u0447\u0435\u0440\u0435\u0437 \u0433\u0435\u0442\u0442\u0435\u0440\u044b \u043f\u0440\u043e\u043a\u0441\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0437\u0434\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>toJS<\/code>. \u041e\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u0441\u0435 \u043f\u0440\u043e\u043a\u0441\u0438 \u0437\u0430\u043c\u0435\u043d\u0435\u043d\u044b \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f. \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043e\u043d\u0430 \u0447\u0438\u0442\u0430\u0435\u0442 \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u2013 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u0433\u0435\u0442\u0442\u0435\u0440\u044b.<\/p>\n<p><\/p>\n<p>\u0412 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 popup \u0441\u043d\u043e\u0432\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u044e\u0447\u0435\u0439. \u041d\u0430 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u043e\u043d\u0438 \u043f\u043e\u043f\u0430\u043b\u0438 \u0435\u0449\u0435 \u0438 \u0432 localStorage:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/c97cd96bbdf33856704c30399bcddaed.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u041f\u0440\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 background-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043c\u0435\u0441\u0442\u0435.<\/p>\n<p><\/p>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/siemarell\/extension-demo\/tree\/app-state\">\u0437\u0434\u0435\u0441\u044c<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2 id=\"bezopasnoe-hranenie-privatnyh-klyuchey\">\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u043a\u043b\u044e\u0447\u0435\u0439<\/h2>\n<p><\/p>\n<p>\u0425\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435 \u043a\u043b\u044e\u0447\u0438 \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0432\u0438\u0434\u0435 \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e: \u0432\u0441\u0435\u0433\u0434\u0430 \u0435\u0441\u0442\u044c \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u044c \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0432\u0430\u0441 \u0432\u0437\u043b\u043e\u043c\u0430\u044e\u0442, \u043f\u043e\u043b\u0443\u0447\u0430\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0432\u0430\u0448\u0435\u043c\u0443 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0443 \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 localStorage \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u043b\u044e\u0447\u0438 \u0432 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u043f\u0430\u0440\u043e\u043b\u0435\u043c \u0432\u0438\u0434\u0435.<\/p>\n<p><\/p>\n<p>\u0414\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0441\u0442\u0435\u0439\u0442 locked, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043a\u043b\u044e\u0447\u0430\u043c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0432\u0441\u0435\u043c. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0432 \u0441\u0442\u0435\u0439\u0442 locked \u043f\u043e \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u0443.<\/p>\n<p><\/p>\n<p>Mobx \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0430 \u0438\u0445 \u043e\u0441\u043d\u043e\u0432\u0435. \u042d\u0442\u043e \u2014 \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0435 computed properties. \u0418\u0445 \u043c\u043e\u0436\u043d\u043e \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0441 view \u0432 \u0431\u0430\u0437\u0430\u0445 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {observable, action} from 'mobx';\nimport {setupDnode} from \".\/utils\/setupDnode\";\n\/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u044b \u0434\u043b\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0433\u043e \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u0440\u043e\u043a. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 crypto-js\nimport {encrypt, decrypt} from \".\/utils\/cryptoUtils\";\n\nexport class SignerApp {\n    constructor(initState = {}) {\n        this.store = observable.object({\n            \/\/ \u0425\u0440\u0430\u043d\u0438\u043c \u043f\u0430\u0440\u043e\u043b\u044c \u0438 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u044e\u0447\u0438. \u0415\u0441\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c null - \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 locked\n            password: null,\n            vault: initState.vault,\n\n            \/\/ \u0413\u0435\u0442\u0442\u0435\u0440\u044b \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043c\u044b\u0445 \u043f\u043e\u043b\u0435\u0439. \u041c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u044e \u0441 view \u0432 \u0431\u0434.\n            get locked(){\n                return this.password == null\n            },\n            get keys(){\n                return this.locked ?\n                    undefined :\n                    SignerApp._decryptVault(this.vault, this.password)\n            },\n            get initialized(){\n                return this.vault !== undefined\n            }\n        })\n    }\n    \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0443\u0441\u0442\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u043d\u043e\u0432\u044b\u043c \u043f\u0430\u0440\u043e\u043b\u0435\u043c\n    @action\n    initVault(password){\n        this.store.vault = SignerApp._encryptVault([], password)\n    }\n    @action\n    lock() {\n        this.store.password = null\n    }\n    @action\n    unlock(password) {\n        this._checkPassword(password);\n        this.store.password = password\n    }\n    @action\n    addKey(key) {\n        this._checkLocked();\n        this.store.vault = SignerApp._encryptVault(this.store.keys.concat(key), this.store.password)\n    }\n    @action\n    removeKey(index) {\n        this._checkLocked();\n        this.store.vault = SignerApp._encryptVault([\n                ...this.store.keys.slice(0, index),\n                ...this.store.keys.slice(index + 1)\n            ],\n            this.store.password\n        )\n    }\n\n    ... \/\/ \u043a\u043e\u0434 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0438 api\n\n    \/\/ private\n    _checkPassword(password) {\n        SignerApp._decryptVault(this.store.vault, password);\n    }\n\n    _checkLocked() {\n        if (this.store.locked){\n            throw new Error('App is locked')\n        }\n    }\n\n    \/\/ \u041c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0438\/\u0434\u0435\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0438 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430\n    static _encryptVault(obj, pass){\n        const jsonString = JSON.stringify(obj)\n        return encrypt(jsonString, pass)\n    }\n\n    static _decryptVault(str, pass){\n        if (str === undefined){\n            throw new Error('Vault not initialized')\n        }\n        try {\n            const jsonString = decrypt(str, pass)\n            return JSON.parse(jsonString)\n        }catch (e) {\n            throw new Error('Wrong password')\n        }\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0445\u0440\u0430\u043d\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u044e\u0447\u0438 \u0438 \u043f\u0430\u0440\u043e\u043b\u044c. \u0412\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442\u0441\u044f. \u041f\u0435\u0440\u0435\u0432\u043e\u0434 \u0432 \u0441\u0442\u0435\u0439\u0442 locked \u043c\u044b \u0434\u0435\u043b\u0430\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u043e\u043b\u044f \u0438\u0437 \u0441\u0442\u0435\u0439\u0442\u0430. \u0412 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u043c API \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430.<\/p>\n<p><\/p>\n<p>\u0414\u043b\u044f \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b <noindex><a rel=\"nofollow\" href=\"https:\/\/www.npmjs.com\/package\/crypto-js\">\u0443\u0442\u0438\u043b\u0438\u0442\u044b \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0441rypto-js<\/a><\/noindex>:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import CryptoJS from 'crypto-js'\n\n\/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0441\u043b\u043e\u0436\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0431\u043e\u0440\u0430 \u043f\u0430\u0440\u043e\u043b\u044f \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u043e\u043c. \u041d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043f\u0430\u0440\u043e\u043b\u044f \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a\u0443 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c 5000 \u0445\u0435\u0448\u0435\u0439\nfunction strengthenPassword(pass, rounds = 5000) {\n    while (rounds-- &gt; 0){\n        pass = CryptoJS.SHA256(pass).toString()\n    }\n    return pass\n}\n\nexport function encrypt(str, pass){\n    const strongPass = strengthenPassword(pass);\n    return CryptoJS.AES.encrypt(str, strongPass).toString()\n}\n\nexport function decrypt(str, pass){\n    const strongPass = strengthenPassword(pass)\n    const decrypted = CryptoJS.AES.decrypt(str, strongPass);\n    return decrypted.toString(CryptoJS.enc.Utf8)\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0423 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0435\u0441\u0442\u044c idle API, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u2014 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0435\u0439\u0442\u0430. \u0421\u0442\u0435\u0439\u0442, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c <code>idle<\/code>, <code>active<\/code> \u0438 <code>locked<\/code>. \u0414\u043b\u044f idle \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0442\u0430\u0439\u043c\u0430\u0443\u0442, \u0430 locked \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441\u0430\u043c\u0430 \u041e\u0421. \u0422\u0430\u043a\u0436\u0435 \u043c\u044b \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u043c \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432 localStorage:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {reaction, toJS} from 'mobx';\nimport {extensionApi} from \".\/utils\/extensionApi\";\nimport {PortStream} from \".\/utils\/PortStream\";\nimport {SignerApp} from \".\/SignerApp\";\nimport {loadState, saveState} from \".\/utils\/localStorage\";\n\nconst DEV_MODE = process.env.NODE_ENV !== 'production';\nconst IDLE_INTERVAL = 30;\n\nsetupApp();\n\nfunction setupApp() {\n    const initState = loadState();\n    const app = new SignerApp(initState);\n\n    if (DEV_MODE) {\n        global.app = app;\n    }\n\n    \/\/ \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u044f\u0432\u043d\u043e \u0443\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u043e\u043b\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f, reaction \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\n    reaction(\n        () =&gt; ({\n            vault: app.store.vault\n        }),\n        saveState\n    );\n\n    \/\/ \u0422\u0430\u0439\u043c\u0430\u0443\u0442 \u0431\u0435\u0437\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f, \u043a\u043e\u0433\u0434\u0430 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435\n    extensionApi.idle.setDetectionInterval(IDLE_INTERVAL);\n    \/\/ \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u043b\u043e\u0447\u0438\u043b \u044d\u043a\u0440\u0430\u043d \u0438\u043b\u0438 \u0431\u0435\u0437\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0430 \u043b\u043e\u0447\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\n    extensionApi.idle.onStateChanged.addListener(state =&gt; {\n        if (['locked', 'idle'].indexOf(state) &gt; -1) {\n            app.lock()\n        }\n    });\n\n    \/\/ Connect to other contexts\n    extensionApi.runtime.onConnect.addListener(connectRemote);\n\n    function connectRemote(remotePort) {\n        const processName = remotePort.name;\n        const portStream = new PortStream(remotePort);\n        if (processName === 'contentscript') {\n            const origin = remotePort.sender.url\n            app.connectPage(portStream, origin)\n        } else {\n            app.connectPopup(portStream)\n        }\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>\u041a\u043e\u0434 \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u0448\u0430\u0433\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/siemarell\/extension-demo\/tree\/secure-keys\">\u0437\u0434\u0435\u0441\u044c<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h3 id=\"tranzakcii\">\u0422\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438<\/h3>\n<p><\/p>\n<p>\u0418\u0442\u0430\u043a, \u043c\u044b \u043f\u043e\u0434\u043e\u0448\u043b\u0438 \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u0433\u043b\u0430\u0432\u043d\u043e\u043c\u0443: \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 \u0432 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d\u0435. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d WAVES \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.npmjs.com\/package\/@waves\/waves-transactions\">waves-transactions<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u0441\u0442\u0435\u0439\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c, \u0437\u0430\u0442\u0435\u043c \u2014 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u0438 \u0438 \u043e\u0442\u043a\u0430\u0437\u0430:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {action, observable, reaction} from 'mobx';\nimport uuid from 'uuid\/v4';\nimport {signTx} from '@waves\/waves-transactions'\nimport {setupDnode} from \".\/utils\/setupDnode\";\nimport {decrypt, encrypt} from \".\/utils\/cryptoUtils\";\n\nexport class SignerApp {\n\n    ...\n\n    @action\n    newMessage(data, origin) {\n        \/\/ \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0441 id, \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u043c, \u0432\u044b\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438 \u0442\u0434.\n        const message = observable.object({\n            id: uuid(), \/\/ \u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u044e uuid\n            origin, \/\/ Origin \u0431\u0443\u0434\u0435\u043c \u0432\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435\n            data, \/\/\n            status: 'new', \/\/ \u0421\u0442\u0430\u0442\u0443\u0441\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u0447\u0435\u0442\u044b\u0440\u0435: new, signed, rejected \u0438 failed\n            timestamp: Date.now()\n        });\n        console.log(`new message: ${JSON.stringify(message, null, 2)}`);\n\n        this.store.messages.push(message);\n\n        \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043f\u0440\u043e\u043c\u0438\u0441 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e mobx \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0430\u0442\u0443\u0441 \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043c\u044b \u0437\u0430\u0440\u0435\u0437\u043e\u043b\u0432\u0438\u043c \u0435\u0433\u043e\n        return new Promise((resolve, reject) =&gt; {\n            reaction(\n                () =&gt; message.status, \/\/\u0411\u0443\u0434\u0435\u043c \u043e\u0431\u0441\u0435\u0440\u0432\u0438\u0442\u044c \u0441\u0442\u0430\u0442\u0443\u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u044f\n                (status, reaction) =&gt; { \/\/ \u0432\u0442\u043e\u0440\u043e\u0439 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 \u044d\u0442\u043e \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0441\u0430\u043c reaction, \u0447\u0442\u043e\u0431\u044b \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0430\n                    switch (status) {\n                        case 'signed':\n                            resolve(message.data);\n                            break;\n                        case 'rejected':\n                            reject(new Error('User rejected message'));\n                            break;\n                        case 'failed':\n                            reject(new Error(message.err.message));\n                            break;\n                        default:\n                            return\n                    }\n                    reaction.dispose()\n                }\n            )\n        })\n    }\n    @action\n    approve(id, keyIndex = 0) {\n        const message = this.store.messages.find(msg =&gt; msg.id === id);\n        if (message == null) throw new Error(`No msg with id:${id}`);\n        try {\n            message.data = signTx(message.data, this.store.keys[keyIndex]);\n            message.status = 'signed'\n        } catch (e) {\n            message.err = {\n                stack: e.stack,\n                message: e.message\n            };\n            message.status = 'failed'\n            throw e\n        }\n    }\n    @action\n    reject(id) {\n        const message = this.store.messages.find(msg =&gt; msg.id === id);\n        if (message == null) throw new Error(`No msg with id:${id}`);\n        message.status = 'rejected'\n    }\n\n    ...\n}<\/code><\/pre>\n<p><\/p>\n<p>\u041f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043d\u0435\u0433\u043e \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435, \u0434\u0435\u043b\u0430\u0435\u043c <code>observable<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 <code>store.messages<\/code>.<\/p>\n<p><\/p>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c <code>observable<\/code> \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0442\u043e mobx \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u044d\u0442\u043e \u0441\u0430\u043c \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 messages. \u041e\u0434\u043d\u0430\u043a\u043e \u043e\u043d \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443 \u043d\u0430\u0441 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0438, \u0430 \u043e\u043d\u0430 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0448\u0430\u0433\u0430.<\/p>\n<p><\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043f\u0440\u043e\u043c\u0438\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u0442\u0441\u044f \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u0417\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u043c \u0441\u043b\u0435\u0434\u0438\u0442 reaction, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0430\u043c \u0441\u0435\u0431\u044f &#171;\u0443\u0431\u044c\u0435\u0442&#187; \u043f\u0440\u0438 \u0441\u043c\u0435\u043d\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u0430.<\/p>\n<p><\/p>\n<p>\u041a\u043e\u0434 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 <code>approve<\/code> \u0438 <code>reject<\/code> \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442: \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043c\u0435\u043d\u044f\u0435\u043c \u0441\u0442\u0430\u0442\u0443\u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0432 \u0435\u0433\u043e, \u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e.<\/p>\n<p><\/p>\n<p>Approve \u0438 reject \u043c\u044b \u0432\u044b\u043d\u043e\u0441\u0438\u043c \u0432 API UI, newMessage \u2014 \u0432 API \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">export class SignerApp {\n    ...\n    popupApi() {\n        return {\n            addKey: async (key) =&gt; this.addKey(key),\n            removeKey: async (index) =&gt; this.removeKey(index),\n\n            lock: async () =&gt; this.lock(),\n            unlock: async (password) =&gt; this.unlock(password),\n            initVault: async (password) =&gt; this.initVault(password),\n\n            approve: async (id, keyIndex) =&gt; this.approve(id, keyIndex),\n            reject: async (id) =&gt; this.reject(id)\n        }\n    }\n\n    pageApi(origin) {\n        return {\n            signTransaction: async (txParams) =&gt; this.newMessage(txParams, origin)\n        }\n    }\n\n    ...\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/b5c124bcbfdf3d4ff59f89a1dfa7c563.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u0412 \u0446\u0435\u043b\u043e\u043c \u0432\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e, \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/siemarell\/extension-demo\/tree\/transactions\">\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 UI<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2 id=\"ui\">UI<\/h2>\n<p><\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443 \u043d\u0443\u0436\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0442\u0435\u0439\u0442\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 UI \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c <code>observable<\/code> \u0441\u0442\u0435\u0439\u0442 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 API \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u044d\u0442\u043e\u0442 \u0441\u0442\u0435\u0439\u0442 \u043c\u0435\u043d\u044f\u0442\u044c. \u0414\u043e\u0431\u0430\u0432\u0438\u043c <code>observable<\/code> \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 API, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043e\u0442 background:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {observable} from 'mobx'\nimport {extensionApi} from \".\/utils\/extensionApi\";\nimport {PortStream} from \".\/utils\/PortStream\";\nimport {cbToPromise, setupDnode, transformMethods} from \".\/utils\/setupDnode\";\nimport {initApp} from \".\/ui\/index\";\n\nconst DEV_MODE = process.env.NODE_ENV !== 'production';\n\nsetupUi().catch(console.error);\n\nasync function setupUi() {\n    \/\/ \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u0441\u044f \u043a \u043f\u043e\u0440\u0442\u0443, \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0438\u0437 \u043d\u0435\u0433\u043e \u0441\u0442\u0440\u0438\u043c\n    const backgroundPort = extensionApi.runtime.connect({name: 'popup'});\n    const connectionStream = new PortStream(backgroundPort);\n\n    \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0443\u0441\u0442\u043e\u0439 observable \u0434\u043b\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f background'a\n    let backgroundState = observable.object({});\n    const api = {\n        \/\/\u041e\u0442\u0434\u0430\u0435\u043c \u0431\u0435\u043a\u0433\u0440\u0430\u0443\u043d\u0434\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c observable\n        updateState: async state =&gt; {\n            Object.assign(backgroundState, state)\n        }\n    };\n\n    \/\/ \u0414\u0435\u043b\u0430\u0435\u043c RPC \u043e\u0431\u044a\u0435\u043a\u0442\n    const dnode = setupDnode(connectionStream, api);\n    const background = await new Promise(resolve =&gt; {\n        dnode.once('remote', remoteApi =&gt; {\n            resolve(transformMethods(cbToPromise, remoteApi))\n        })\n    });\n\n    \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 background observable \u0441\u043e \u0441\u0442\u0435\u0439\u0442\u043e\u043c\n    background.state = backgroundState;\n\n    if (DEV_MODE) {\n        global.background = background;\n    }\n\n    \/\/ \u0417\u0430\u043f\u0443\u0441\u043a \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\n    await initApp(background)\n}\n<\/code><\/pre>\n<p><\/p>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435 \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0440\u0435\u043d\u0434\u0435\u0440 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u042d\u0442\u043e react-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. Background-\u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 props. \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0438 store \u0434\u043b\u044f \u0441\u0442\u0435\u0439\u0442\u0430, \u043d\u043e \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">import {render} from 'react-dom'\nimport App from '.\/App'\nimport React from \"react\";\n\n\/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 background \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442 \u0432\u0435 props\nexport async function initApp(background){\n    render(\n        &lt;App background={background}\/&gt;,\n        document.getElementById('app-content')\n    );\n}\n<\/code><\/pre>\n<p><\/p>\n<p>\u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e mobx \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0440\u0435\u043d\u0434\u0435\u0440 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445. \u041c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0435\u0448\u0430\u0435\u043c \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 observer \u0438\u0437 \u043f\u0430\u043a\u0435\u0442\u0430 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.npmjs.com\/package\/mobx-react\">mobx-react<\/a><\/noindex> \u043d\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442, \u0438 \u0440\u0435\u043d\u0434\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043b\u044e\u0431\u044b\u0445 observable, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442. \u041d\u0435 \u043d\u0443\u0436\u043d\u043e \u043d\u0438\u043a\u0430\u043a\u0438\u0445 mapStateToProps \u0438\u043b\u0438 connect, \u043a\u0430\u043a \u0432 redux. \u0412\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441\u0440\u0430\u0437\u0443 &#171;\u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438&#187;:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">import React, {Component, Fragment} from 'react'\nimport {observer} from \"mobx-react\";\nimport Init from '.\/components\/Initialize'\nimport Keys from '.\/components\/Keys'\nimport Sign from '.\/components\/Sign'\nimport Unlock from '.\/components\/Unlock'\n\n@observer \/\/ \u0423 \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u0442\u0430 \u0441 \u044d\u0442\u0438\u043c \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0437\u0432\u0430\u043d \u043c\u0435\u0442\u043e\u0434 render, \u0435\u0441\u043b\u0438 \u0431\u0443\u0434\u0443\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u044b observable \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043d \u0441\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f\nexport default class App extends Component {\n\n    \/\/ \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u043b\u043e\u0433\u0438\u043a\u0443 \u0440\u0435\u043d\u0434\u0435\u0440\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u0432 \u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u0438 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0442\u0435\u0440\u043d\u0430\u0440\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b,\n    \/\/ \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c observable \u0438 \u043c\u0435\u0442\u043e\u0434\u044b background \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a \u0442\u0435\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\n    render() {\n        const {keys, messages, initialized, locked} = this.props.background.state;\n        const {lock, unlock, addKey, removeKey, initVault, deleteVault, approve, reject} = this.props.background;\n\n        return &lt;Fragment&gt;\n            {!initialized\n                ?\n                &lt;Init onInit={initVault}\/&gt;\n                :\n                locked\n                    ?\n                    &lt;Unlock onUnlock={unlock}\/&gt;\n                    :\n                    messages.length &gt; 0\n                        ?\n                        &lt;Sign keys={keys} message={messages[messages.length - 1]} onApprove={approve} onReject={reject}\/&gt;\n                        :\n                        &lt;Keys keys={keys} onAdd={addKey} onRemove={removeKey}\/&gt;\n            }\n            &lt;div&gt;\n                {!locked &amp;&amp; &lt;button onClick={() =&gt; lock()}&gt;Lock App&lt;\/button&gt;}\n                {initialized &amp;&amp; &lt;button onClick={() =&gt; deleteVault()}&gt;Delete all keys and init&lt;\/button&gt;}\n            &lt;\/div&gt;\n        &lt;\/Fragment&gt;\n    }\n}<\/code><\/pre>\n<p><\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 \u043a\u043e\u0434\u0435 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/siemarell\/extension-demo\/tree\/master\/src\/ui\">\u0432 \u043f\u0430\u043f\u043a\u0435 UI<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u0441\u0442\u0435\u0439\u0442\u0430 \u0434\u043b\u044f UI \u0438 \u043f\u0440\u0438 \u0435\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043e\u043f\u043e\u0432\u0435\u0449\u0430\u0442\u044c UI. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u0435\u0442\u043e\u0434 <code>getState<\/code> \u0438 <code>reaction<\/code>, \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 <code>remote.updateState<\/code>:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">import {action, observable, reaction} from 'mobx';\nimport uuid from 'uuid\/v4';\nimport {signTx} from '@waves\/waves-transactions'\nimport {setupDnode} from \".\/utils\/setupDnode\";\nimport {decrypt, encrypt} from \".\/utils\/cryptoUtils\";\n\nexport class SignerApp {\n\n    ...\n\n    \/\/ public\n    getState() {\n        return {\n            keys: this.store.keys,\n            messages: this.store.newMessages,\n            initialized: this.store.initialized,\n            locked: this.store.locked\n        }\n    }\n\n    ...\n\n    \/\/\n    connectPopup(connectionStream) {\n        const api = this.popupApi();\n        const dnode = setupDnode(connectionStream, api);\n\n        dnode.once('remote', (remote) =&gt; {\n            \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c reaction \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0435\u0439\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u0443 \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0443 \u0438 \u043e\u0431\u043d\u043e\u0432\u0438\u0442 \u0441\u0442\u0435\u0439\u0442 \u0432 ui \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435\n            const updateStateReaction = reaction(\n                () =&gt; this.getState(),\n                (state) =&gt; remote.updateState(state),\n                \/\/ \u0422\u0440\u0435\u0442\u044c\u0438\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b. fireImmediatly \u0437\u043d\u0430\u0447\u0438\u0442 \u0447\u0442\u043e reaction \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u0439 \u0440\u0430\u0437 \u0441\u0440\u0430\u0437\u0443.\n                \/\/ \u042d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435. Delay \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c debounce\n                {fireImmediately: true, delay: 500}\n            );\n            \/\/ \u0423\u0434\u0430\u043b\u0438\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 \u043f\u0440\u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\n            dnode.once('end', () =&gt; updateStateReaction.dispose())\n\n        })\n    }\n\n    ...\n}<\/code><\/pre>\n<p><\/p>\n<p>\u041f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 <code>remote<\/code> \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f <code>reaction<\/code> \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u0442\u0435\u0439\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 UI.<\/p>\n<p><\/p>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0448\u0442\u0440\u0438\u0445 \u2014 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043d\u0430 \u0438\u043a\u043e\u043d\u043a\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f:<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">function setupApp() {\n...\n\n    \/\/ Reaction \u043d\u0430 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0441\u0442\u0430 \u0431\u0435\u0434\u0436\u0430.\n    reaction(\n        () =&gt; app.store.newMessages.length &gt; 0 ? app.store.newMessages.length.toString() : '',\n        text =&gt; extensionApi.browserAction.setBadgeText({text}),\n        {fireImmediately: true}\n    );\n\n...\n}<\/code><\/pre>\n<p><\/p>\n<p>\u0418\u0442\u0430\u043a, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0433\u043e\u0442\u043e\u0432\u043e. \u0412\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043c\u043e\u0433\u0443\u0442 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043f\u0438\u0441\u044c \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/dae670b56bf9cbf860e710a112180132.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\" src=\"\/wp-content\/uploads\/2019\/05\/131ed6d6733c25c254d887a42f55a446.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u041a\u043e\u0434 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043f\u043e \u044d\u0442\u043e\u0439 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/siemarell\/extension-demo\/tree\/ui\">\u0441\u0441\u044b\u043b\u043a\u0435<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><strong>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/strong><\/p>\n<p><\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0434\u043e\u0447\u0438\u0442\u0430\u043b\u0438 \u0441\u0442\u0430\u0442\u044c\u044e \u0434\u043e \u043a\u043e\u043d\u0446\u0430, \u043d\u043e \u0443 \u0432\u0430\u0441 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0434\u0430\u0442\u044c \u0438\u0445 \u0432 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/siemarell\/extension-demo\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c<\/a><\/noindex>. \u0422\u0430\u043c \u0436\u0435 \u0432\u044b \u043d\u0430\u0439\u0434\u0435\u0442\u0435 \u043a\u043e\u043c\u043c\u0438\u0442\u044b \u043f\u043e\u0434 \u043a\u0430\u0436\u0434\u044b\u0439 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0439 \u0448\u0430\u0433. <\/p>\n<p><\/p>\n<p>\u0410 \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u043e\u0434 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f, \u0442\u043e \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u044d\u0442\u043e <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wavesplatform\/WavesKeeper\">\u0437\u0434\u0435\u0441\u044c<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><strong>\u041a\u043e\u0434, \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u043e\u0442 <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/users\/siemarell\/\" class=\"user_link\">siemarell<\/a><\/noindex><\/strong><\/p>\n<p>\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/waves\/blog\/451796\/\">habr.com<\/a><\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043d\u043e\u0439 &#171;\u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439&#187; \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u0434\u043b\u044f \u0434\u0435\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u043e: \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043b\u043e\u0433\u0438\u043d\u0430\u043c\u0438 \u0438 \u043f\u0430\u0440\u043e\u043b\u044f\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443 \u0441\u0430\u043c\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0430 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0438\u0445 \u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430. \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440. \u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d-\u0441\u0435\u0442\u0438, \u0433\u0434\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0438 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 2 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":25333,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-33644","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043d\u043e\u0439 &quot;\u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439&quot; \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u0434\u043b\u044f \u0434\u0435\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u043e: \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043b\u043e\u0433\u0438\u043d\u0430\u043c\u0438 \u0438 \u043f\u0430\u0440\u043e\u043b\u044f\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443 \u0441\u0430\u043c\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0430 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0438\u0445 \u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430. \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440. \u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d-\u0441\u0435\u0442\u0438, \u0433\u0434\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0438 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 2\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/pishem-bezopasnoe-brauzernoe-rasshirenie\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043d\u043e\u0439 &quot;\u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439&quot; \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u0434\u043b\u044f \u0434\u0435\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u043e: \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043b\u043e\u0433\u0438\u043d\u0430\u043c\u0438 \u0438 \u043f\u0430\u0440\u043e\u043b\u044f\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443 \u0441\u0430\u043c\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0430 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0438\u0445 \u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430. \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440. \u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d-\u0441\u0435\u0442\u0438, \u0433\u0434\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0438 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 2\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/pishem-bezopasnoe-brauzernoe-rasshirenie\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:53:55+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:53:55+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Sichere Browsererweiterungen entwickeln | ProHoster","description":"Im Gegensatz zur verbreiteten \"Client-Server\"-Architektur zeichnen sich dezentrale Anwendungen durch Folgendes aus: Das Fehlen der Notwendigkeit, eine Datenbank mit Benutzernamen und Passw\u00f6rtern zu speichern. Der Zugriff erfolgt ausschlie\u00dflich \u00fcber die Benutzer selbst, und die Best\u00e4tigung ihrer Authentizit\u00e4t erfolgt auf Protokollebene. Es besteht keine Notwendigkeit, einen Server zu verwenden. Die Logik der Anwendung kann im Blockchain-Netzwerk ausgef\u00fchrt werden, wo auch die Speicherung der ben\u00f6tigten Datenmenge m\u00f6glich ist. Es gibt 2","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/pishem-bezopasnoe-brauzernoe-rasshirenie","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041f\u0438\u0448\u0435\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 | ProHoster","og:description":"\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043d\u043e\u0439 &quot;\u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439&quot; \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u0434\u043b\u044f \u0434\u0435\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u043e: \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043b\u043e\u0433\u0438\u043d\u0430\u043c\u0438 \u0438 \u043f\u0430\u0440\u043e\u043b\u044f\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443 \u0441\u0430\u043c\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0430 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0438\u0445 \u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430. \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440. \u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d-\u0441\u0435\u0442\u0438, \u0433\u0434\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0438 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 2","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/pishem-bezopasnoe-brauzernoe-rasshirenie","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:53:55+00:00","article:modified_time":"2019-10-31T18:53:55+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"33644","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 16:09:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 02:36:35","updated":"2026-01-21 16:09:19"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/33644","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=33644"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/33644\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/25333"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=33644"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=33644"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=33644"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}