├── src
├── background.html
├── icon16.png
├── icon19.png
├── icon48.png
├── icon128.png
├── background.js
├── options.html
├── manifest.json
├── style.css
├── json2.js
└── options.js
├── chrome-user-agent.crx
└── README.md
/src/background.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jugglinmike/chrome-user-agent/HEAD/src/icon16.png
--------------------------------------------------------------------------------
/src/icon19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jugglinmike/chrome-user-agent/HEAD/src/icon19.png
--------------------------------------------------------------------------------
/src/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jugglinmike/chrome-user-agent/HEAD/src/icon48.png
--------------------------------------------------------------------------------
/src/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jugglinmike/chrome-user-agent/HEAD/src/icon128.png
--------------------------------------------------------------------------------
/chrome-user-agent.crx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jugglinmike/chrome-user-agent/HEAD/chrome-user-agent.crx
--------------------------------------------------------------------------------
/src/background.js:
--------------------------------------------------------------------------------
1 | var requestFilter = {
2 | urls: [
3 | ""
4 | ]
5 | };
6 |
7 | chrome.webRequest.onBeforeSendHeaders.addListener(function(details) {
8 | var headers = details.requestHeaders;
9 | if( !localStorage['user-agent'] ) {
10 | return;
11 | }
12 | for(var i = 0, l = headers.length; i < l; ++i) {
13 | if( headers[i].name == 'User-Agent' ) {
14 | break;
15 | }
16 | }
17 | if(i < headers.length) {
18 | headers[i].value = localStorage['user-agent'];
19 | }
20 | return {requestHeaders: headers};
21 | }, requestFilter, ['requestHeaders','blocking']);
--------------------------------------------------------------------------------
/src/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Chrome UA Options
9 |
18 |
19 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Chrome User-Agent",
3 | "version": "0.1.0",
4 | "description": "Modify the user-agent string sent with HTTP requests. Go to the options page to select a new string or create your own.",
5 | "homepage_url": "http://jugglinmike.github.com/chrome-user-agent/",
6 | "icons": {
7 | "16": "icon16.png",
8 | "48": "icon48.png",
9 | "128": "icon128.png"
10 | },
11 |
12 | "options_page": "options.html",
13 | "background_page": "background.html",
14 | "browser_action": {
15 | "default_icon": "icon19.png",
16 | "popup": "options.html"
17 | },
18 | "permissions": [
19 | "webRequest",
20 | "webRequestBlocking",
21 | "",
22 | "tabs"
23 | ]
24 | }
--------------------------------------------------------------------------------
/src/style.css:
--------------------------------------------------------------------------------
1 | #control_panel {
2 | background-color:#0099cc;
3 | font-family:Arial,sans-serif;
4 | width:300px;
5 | } #control_panel h1 {
6 | color:#eeeeee;
7 | font-size:20pt;
8 | font-weight:bold;
9 | } #control_panel h2 {
10 | display:block;
11 | font-size:10pt;
12 | font-weight:bold;
13 | margin:8px 0px 3px 0px;
14 | padding:0px;
15 | } #control_panel ul {
16 | display:block;
17 | list-style-type:none;
18 | margin:0px 0px 8px 0px;
19 | padding:0px;
20 | } #control_panel li {
21 | display:inline;
22 | margin:0px 4px 0px 0px;
23 | padding:0px;
24 | white-space:nowrap;
25 | } #control_panel input {
26 | margin:0px 4px 0px 0px;
27 | padding:0px;
28 | } #control_panel input[type=text] {
29 | background-color:#0099cc;
30 | border:1px solid #ffffff;
31 | padding:2px;
32 | } #control_panel input[type=button] {
33 | background-color:#0099cc;
34 | border:solid 1px #eeeeee;
35 | color:#eeeeee;
36 | margin:3px;
37 | padding:3px;
38 | } #control_panel input::selection {
39 | background:#ffffff;
40 | } #control_panel textarea {
41 | background:inherit;
42 | border:solid 1px #eeeeee;
43 | height:4em;
44 | width:100%;
45 | } #control_panel label {
46 | cursor:pointer;
47 | display:inline;
48 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # This project has been deprecated.
2 |
3 | Starting with version 17, the Google Chrome browser ships with support for
4 | modifying the User-Agent string. ([Click here for the Chromium
5 | issue](http://code.google.com/p/chromium/issues/detail?id=67063) and [here for
6 | more info on the
7 | feature](http://techdows.com/2011/12/google-chrome-now-has-built-in-user-agent-switcher.html).)
8 | This renders the dedicated user-agent switching extension obsolete, but the
9 | approach outlined here may still be relevant in the context of a larger
10 | extension.
11 |
12 | Chrome User-Agent Modifier Extension
13 | ====================================
14 |
15 | Allows you to re-set the "User-Agent" string in Chrome's HTTP request headers.
16 |
17 | Installation Instructions
18 | -------------------------
19 |
20 | **Download the Extension.** You can get the latest version of the [extension
21 | here](https://raw.github.com/jugglinmike/chrome-user-agent/master/chrome-user-agent.crx)
22 | (of course, you'll need [Google Chrome](http://www.google.com/chrome) installed
23 | first).
24 |
25 | **Install the Application.** Drag the extension file (it is named
26 | 'chrome-ua-modifier.crx' by default) into a Chrome browser window.
27 |
28 | How to Run
29 | ----------
30 |
31 | **Changing Your User-Agent.** The extension options can be accessed either by
32 | selecting "Options" under the extension's entry on chrome://extensions or clicking on the
34 | extension's logo (
) next to Chrome's omnibox. Select
35 | any entry from the device list, and all future HTTP requests will be sent with
36 | the user-agent string displayed in the text area. Select "default" to use your
37 | default user-agent string.
38 |
39 | **Adding/Modifying "Devices".** Click "Add a Device" to create a new device--be
40 | sure to type a device name in the text area that appears. (You can double-click
41 | any device to change its name.) If you want to change the User-Agent string
42 | associated with any device, select it from the list and modify the text in the
43 | "Current User-Agent" text area. (I have found this page on zytrax.com to be a great resource for valid
46 | user-agent strings.)
47 |
48 | **Deleting "Devices".** If you no longer need a saved device, simply
49 | double-click on its entry in the list and clear the text area.
50 |
--------------------------------------------------------------------------------
/src/json2.js:
--------------------------------------------------------------------------------
1 | var JSON;if(!JSON){JSON={};}
2 | (function(){"use strict";function f(n){return n<10?'0'+n:n;}
3 | if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+
4 | f(this.getUTCMonth()+1)+'-'+
5 | f(this.getUTCDate())+'T'+
6 | f(this.getUTCHours())+':'+
7 | f(this.getUTCMinutes())+':'+
8 | f(this.getUTCSeconds())+'Z':null;};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}
9 | var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}
10 | function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}
11 | if(typeof rep==='function'){value=rep.call(holder,key,value);}
12 | switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
13 | gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i 1000 ) {
61 | this.lastClicked = now;
62 | return;
63 | }
64 | this.lastClicked = 0;
65 | var deviceID = event.target.getAttribute('for').match(/device_(.+)_button/i)[1],
66 | deviceName = event.target.innerHTML,
67 | textField = dom.createTextField(deviceID, deviceName);
68 | event.target.parentNode.replaceChild(textField, event.target);
69 | textField.focus();
70 | },
71 | nameBlur: function( event ) {
72 | var oldDeviceID,
73 | newDeviceID,
74 | deviceName = event.target.value;
75 |
76 | newDeviceID = deviceName.replace(/ /gi, '_').toLowerCase();
77 | oldDeviceID = event.target.id.match(/device_(.+)_textfield/i);
78 | oldDeviceID = oldDeviceID && oldDeviceID[1];
79 |
80 |
81 | if( oldDeviceID && newDeviceID ) {
82 | // Replace text field with label
83 | var li = document.createElement('li'),
84 | radio = dom.createRadioButton(newDeviceID),
85 | label = dom.createLabel(newDeviceID, deviceName);
86 | li.setAttribute('id', 'device_' +newDeviceID+ '_li');
87 | li.appendChild(radio);
88 | li.appendChild(label);
89 |
90 | event.target.parentNode.parentNode.replaceChild(li, event.target.parentNode);
91 | devices[newDeviceID] = devices[oldDeviceID];
92 | devices[newDeviceID].name = deviceName;
93 | if( oldDeviceID !== newDeviceID ) {
94 | delete devices[oldDeviceID];
95 | }
96 | localStorage['devices'] = JSON.stringify(devices);
97 | } else {
98 | // Delete oldDeviceID's list element
99 | deleteDevice(oldDeviceID);
100 | if( newDeviceID ) {
101 | // Insert new element
102 | while( devices[newDeviceID] ) {
103 | newDeviceID += '-';
104 | }
105 | devices[newDeviceID] = {
106 | name: deviceName,
107 | ua: current_ua_field.value
108 | };
109 | addDeviceElement(newDeviceID, deviceName);
110 | localStorage['devices'] = JSON.stringify(devices);
111 | }
112 | }
113 | },
114 | deviceButtonClick: function(event) {
115 | var regexp = new RegExp('(default' + (deviceListStr ? '|'+deviceListStr : '') + ')', 'i'),
116 | deviceID = event.target.id.match(regexp);
117 | deviceID = deviceID && deviceID[1];
118 | if( !deviceID ) {
119 | return;
120 | }
121 | localStorage['deviceID'] = deviceID;
122 | // Careful setting the localStorage value to prevent setting it with the string 'undefined'
123 | if( devices[deviceID] ) {
124 | localStorage['user-agent'] = elems.current_ua_field.value = devices[deviceID].ua;
125 | } else {
126 | delete localStorage['user-agent'];
127 | elems.current_ua_field.value = '';
128 | }
129 | },
130 | addDeviceButtonClick: function(event) {
131 | var listelement = document.createElement('li'),
132 | textField = dom.createTextField();
133 |
134 | listelement.appendChild(textField);
135 | listelement.setAttribute('id', 'new_device');
136 | elems['device_list'].appendChild(listelement);
137 | elems['device_list'].appendChild(document.createTextNode(' '));
138 | textField.focus();
139 | },
140 | restoreDefaultsButtonClick: function(event) {
141 | var li;
142 | devices = defaultDevices;
143 | delete localStorage['devices'];
144 | while( li = elems.device_list.firstChild ) {
145 | elems.device_list.removeChild(li);
146 | }
147 | deviceStr = '';
148 | loadDevices();
149 | document.getElementById('device_default_button').click();
150 | },
151 | textAreaType: function(event) {
152 | var activeDeviceID = 'default';
153 | for( var deviceID in devices ) {
154 | if( devices.hasOwnProperty(deviceID) ) {
155 | if(document.getElementById('device_' +deviceID+ '_button').checked) {
156 | activeDeviceID = deviceID;
157 | break;
158 | }
159 | }
160 | }
161 | devices[activeDeviceID].ua = localStorage['user-agent'] = event.target.value;
162 | localStorage['devices'] = JSON.stringify(devices);
163 | }
164 | },
165 | addDeviceElement = function( deviceID, deviceName ) {
166 | if( deviceListStr ) {
167 | deviceListStr += '|';
168 | }
169 | deviceListStr += deviceID;
170 | var listItem = document.createElement('li'),
171 | radioButton = dom.createRadioButton(deviceID);
172 | label = dom.createLabel(deviceID, deviceName);
173 |
174 | listItem.appendChild(radioButton);
175 | listItem.appendChild(label);
176 | listItem.setAttribute('id', 'device_' +deviceID+ '_li');
177 | elems['device_list'].appendChild(listItem);
178 | elems['device_list'].appendChild(document.createTextNode(' '));
179 | },
180 | deleteDevice = function( deviceID ) {
181 | var listElementID = deviceID ? 'device_' +deviceID+ '_li' : 'new_device';
182 | listElement = document.getElementById(listElementID);
183 | elems['device_list'].removeChild(listElement);
184 | delete devices[deviceID];
185 | deviceListStr = deviceListStr.replace(deviceID, '');
186 | localStorage['devices'] = JSON.stringify(devices);
187 | },
188 | loadDevices = function() {
189 | // Add the devices, ensuring that "default" is at the top of the list
190 | addDeviceElement('default', 'Default');
191 | for( var deviceID in devices ) {
192 | if( devices.hasOwnProperty(deviceID) && deviceID !== 'default' ) {
193 | addDeviceElement(deviceID, devices[deviceID].name);
194 | }
195 | }
196 | devices['default'] = {'name':'Default', 'ua':''};
197 |
198 | localStorage['deviceID'] = (localStorage['deviceID'] && devices[localStorage['deviceID']]) ? localStorage['deviceID'] : 'default';
199 | },
200 | initForm = function() {
201 | if( localStorage['deviceID'] ) {
202 | document.getElementById('device_' + localStorage['deviceID'] + '_button').setAttribute('checked', true);
203 | elems.current_ua_field.value = (devices[localStorage['deviceID']]) ? devices[localStorage['deviceID']].ua : '';
204 | }
205 | };
206 | document.addEventListener("DOMContentLoaded", function() {
207 | // Grab the DOM elements that need event handlers attached
208 | elem_ids.forEach(function( element_id ) {
209 | elems[element_id] = document.getElementById(element_id);
210 | });
211 |
212 | loadDevices();
213 | initForm();
214 |
215 | elems.add_device_button.addEventListener('click', listeners.addDeviceButtonClick);
216 | elems.restore_defaults_button.addEventListener('click', listeners.restoreDefaultsButtonClick);
217 | elems.current_ua_field.addEventListener('keyup', listeners.textAreaType);
218 | });
219 | })();
--------------------------------------------------------------------------------