Создаем расширения для Google Chrome

в 17:10, , рубрики: Google Chrome, Веб-разработка, расширения chrome, метки: ,

Вчера задался себе таким вопросом: как можно обезопасить мой профиль в Google Chrome и вообще все данные, которые в нем хранятся? Немножко погуглив, я нашел ссылки на кучу расширений (типа этого), которые позволяют устанавливать пароль как на браузер так и на отдельные его профиле (это логично, если знать как работает Chrome в режиме мультипрофильности). Я начал их устанавливать и сразу тесты на баги. И как оказалось ни один из них не хочет адекватно работать в режиме мультипрофильности. Не очень-то долго думая я решил написать собственное расширение и заодно разобраться в Google Chrome API.Немного почитав документацию и разобравшись в принципе работы расширений я приступил к работе.


Принцып написания расширений

Дехто думає, що розширення це щось таке заморське, непідвласне простим людям. Насправді для його написання достатньо всього лиш блокнота, в якому це все писати, і браузера, в якому тестувати написане.Итак, любое расширение для Chrome состоит из следующих составляющих:

  • Файл манифеста manifest.json, в котором записывается информация о приложении;
  • Иные файлы, которые используются в расширении: это могут быть html-странички, скрипты, картинки и т.д.

Для запуска готовой работы нужно всего лишь на стрничке расширений в режиме разработчика загрузить ваше творение.Создаем расширения для Google ChromeИтак, приступим к работе!


Пишем файл манифеста

Файл манифеста хранится в корневой папке проекта и, как вы уже поняли, представляет из себя набор данных в формате JSON. Рассмотрим исхоник манифеста, а после этого я опишу каждый пункт подробнее.

{
	"name": "Profile Guard",
	"description": "Google Chrome profile protection by password",
	"version": "0.1",
	"permissions": [ "tabs" ],
	"background_page": "background.html",
	"icons": {
		"48":"images/bigicon.jpg"
	},
	"browser_action": {
		"default_title": "Profile Guard",
		"default_icon": "images/icon.png",
		"popup": "popup.html"
	}
}

А теперь по порядку:

  • name, description и version — собственно имя расширения, его короткое описание и номер версии;
  • permissions — массив с дополнительными правами расширения на выполнение тех или иных действий. Подробнее почитать можно здесь. В даном случае расширение может знать об открытых вкладках и окнах браузера;
  • background_page — главная страника которая запускается при запуске браузера и работает на фоне;
  • icons — набор иконок разных размеров;
  • browser_action — описание кнопочки на панели инструментов. default_title — текст при наведении на кнопку, default_icon — иконка на кнопке, popup — html-страничка, которая откроется в попапе после клика;

Кроме этих параметров в файле манифеста может быть и много других.


Фоновая страничка

Фоновая страничка будет проверять установлен ли пароль и запрашивать его при открытии браузера или создании окна с неким профилем. От протестированных мною расширений моё отличается именно тем, что более менее адекватно работает в режиме мультипрофильности.Пароль от нашего профиля будет храниться в localStorage['profile_password']. localStorage — это массив, в котором расширение может хранить свои какие-то данные, не беспокоясь о том, что какое-то другое расширение доступиться к этим данным. Для каждого расширения и профиля это отдельная переменная, поэтому можно устанавливать разные пароли на разные профили.

<html>
<head>
<title>Profile Guard background page</title>
</head>
<body onload="pass();">
<script type="text/javascript">
function pass(){
	chrome.windows.getAll(function(wins){
		if(wins.length==1){
			if(localStorage["profile_password"]){
				var pass = prompt("Please enter password:","");
				if(pass!=localStorage["profile_password"]){
					alert("Access denied!");
					chrome.windows.getCurrent(function (window){chrome.windows.remove(window.id)});
				}
			}
		}
	});
}
chrome.windows.onCreated.addListener(function(window){
	pass();
});
</script>
</body>
</html>

Установка и изменение пароля

Создаем расширения для Google ChromeУстанавливать и изменять пароль мы сможем на страничке, которая открывается в попапе popup.html. Изначально пароль не установлен и его можно будет установить. Пожже его можно будет изменить или вовсе удалить. Короче говоря всяческие манипуляции с паролем для входа.Исходник файла запихиваю в спойлер, особо пояснять ничего не буду, по-моему и так всё понятно.

файл popup.html

<html>
<head>
<title>Profile Guard background page</title>
<style>
body {
	font-family: sans-serif;
	background: #f5f5f5;
	color: #666E79;
	width: 250px;
}
div.form {
	background: white;
	border: solid 1px #e8e8e8;
	border-radius: 5px;
}
h1 {
	margin:0;
	padding: 0;
	font-size: 20px;
	text-align: center;
	line-height: 40px;
}
h2 {
	margin: 0 10px;
	padding: 0;
	font-size: 14px;
	line-height: 30px;
}
button {
	border:solid 1px #5E697C;
	background: URL(images/button.jpg);
	color: white;
	font-size: 13px;
	line-height: 22px;
	margin: 10px auto 15px;
	display: block;
	border-radius: 4px;
	cursor: pointer;
	font-weight: bolder;
	text-shadow: rgba(0,0,0,0.2) -1px -1px 0px;
	padding: 1 10px;
}
button:hover {
	background: URL(images/hover.jpg);
}
.newbutton {
	margin: 15px 0;
}
.field {
	padding: 5px 15px;
	text-align:right;
}
label {
	color: #989898;
	font-weight: bolder;
	font-size: 12px;
	float:left;
	line-height: 25px;
}
input {
	width: 135px;
	text-align:left;
}
</style>
<script>

	function view(){
		if(!localStorage["profile_password"]){
			elnewbutton.style.display = "block";
			elnewpass.style.display = "none";
			elchpass.style.display = "none";
		} else {
			elnewbutton.style.display = "none";
			elnewpass.style.display = "none";
			elchpass.style.display = "block";
		}
	}

	function newpass(){
		if(!localStorage["profile_password"]){
			elnewpass.style.display = "block";
			elnewbutton.style.display = "none";
		}
	}
	function newset(){
		if(!localStorage["profile_password"]){
			var pass = npass.value;
			var conf = nconf.value;
			if(pass){
				if(pass!=conf){
					alert("Passwords don't match!");
					npass.value = "";
					nconf.value = "";
				} else {
					localStorage["profile_password"] = pass;
					view();
					alert("Password successfully changed");
				}
			}
		}
	}
	function chset(){
		if(localStorage["profile_password"]){
			var old = cold.value;
			var pass = cpass.value;
			var conf = cconf.value;
			if(old!=localStorage["profile_password"]){
				alert("Old password is entered incorrectly");
				cold.value = "";
			} else {
				if(pass){
					if(pass!=conf){
						cpass.value = "";
						cconf.value = "";
						alert("Passwords do not match!");
					} else {
						localStorage["profile_password"] = pass;
						view();
						alert("Password successfully changed");
					}
				}
			}
		}
	}
	function claerpass(){
		if(localStorage["profile_password"]){
			var old = cold.value;
			if(!old){
				alert("Enter old password first!");
			} else {
				if(old!=localStorage["profile_password"]){
					alert("Old password is entered incorrectly");
					cold.value = "";
				} else {
					localStorage["profile_password"] = "";
					view();
					alert("Password successfully deleted");
				}
			}
		}
	}
</script>
</head>
<body onload="view();">
<div class="form">
<h1>Profile Guard</h1>
</div>
<div class="newbutton" id="newbutton">
<button id="elnewbutton" onclick="newpass();">Set new password</button>
</div>
<div class="newpass form" id="elnewpass" style="display:block;">
<h2>Set password</h2>
<div class="field">
<label>Password</label>
<input type="password" id="npass" />
</div>
<div class="field">
<label>Confirm</label>
<input type="password" id="nconf" />
</div>
<button id="elnewset" onclick="newset();">Set new password</button>
</div>
<div class="newpass form" id="elchpass" style="display:block;">
<h2>Password change</h2>
<div class="field">
<label>Old password</label>
<input type="password" id="cold" />
</div>
<div class="field">
<label>Password</label>
<input type="password" id="cpass" />
</div>
<div class="field">
<label>Confirm</label>
<input type="password" id="cconf" />
</div>
<button id="elchset" onclick="chset();">Change password</button>
<button id="elclear" onclick="claerpass();">Delete password</button>
</div>
</body>
</html>

Завершающий этап

В завершение нам нужно упаковать наше творение, это можна сделать на странице расширений нажав на кнопку «Упаковка расширений». Указав папку с нашим расширением на выходе мы получаем два файла: .crx — файл с самим расширением, .rem — файл с секретным ключом. В придачу вы можете поделится своим творением с людьми, залив его на Chrome WebStore, но для этого нужно заплатить гуглу взнос в размере $5 (но это лишь первый раз, при регистрации).Прошу не судить строго, ведь это моё первое расширение. Скачать исходник можно по ссылке. Уапкованное расширение не даю, так как в хроме можно устанавливать лишь расширения с Вебстора.
Пишите свои замечания и замеченные баги.

Автор: makzimko

* - обязательные к заполнению поля