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