1 /* See license.txt for terms of usage */
  2 
  3 define([
  4     "firebug/lib/locale",
  5     "firebug/lib/xpcom",
  6     "firebug/cookies/cookie",
  7 ],
  8 function(Locale, Xpcom, Cookie) {
  9 
 10 // ********************************************************************************************* //
 11 // Constants
 12 
 13 const Cc = Components.classes;
 14 const Ci = Components.interfaces;
 15 
 16 const windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
 17 
 18 // ********************************************************************************************* //
 19 
 20 const ioService = Xpcom.CCSV("@mozilla.org/network/io-service;1", "nsIIOService");
 21 const versionChecker = Xpcom.CCSV("@mozilla.org/xpcom/version-comparator;1", "nsIVersionComparator");
 22 const appInfo = Xpcom.CCSV("@mozilla.org/xre/app-info;1", "nsIXULAppInfo");
 23 const prompts = Xpcom.CCSV("@mozilla.org/embedcomp/prompt-service;1", "nsIPromptService");
 24 
 25 // ********************************************************************************************* //
 26 
 27 /**
 28  * @dialog Edit cookie dialog implementation. This dialog is used to create a new cookie
 29  * and edit an existing cookies.
 30  */
 31 function EditCookie(win)
 32 {
 33     this.window = win;
 34 }
 35 
 36 EditCookie.prototype =
 37 {
 38     cookie: null,
 39 
 40     onLoad: function()
 41     {
 42         this.createDateTimeField();
 43 
 44         var params = this.window.arguments[0];
 45         this.params = params;
 46         this.cookie = params.cookie;
 47 
 48         this.nameNode = $("fcName", this.window);
 49         this.valueNode = $("fcValue", this.window);
 50         this.domainNode = $("fcDomain", this.window);
 51         this.pathNode = $("fcPath", this.window);
 52         this.expireNode = $("fcExpire", this.window);
 53         this.sessionNode = $("fcSession", this.window);
 54         this.secureNode = $("fcSecure", this.window);
 55         this.httpOnly = $("fcHttpOnly", this.window);
 56         this.URLEncodeValue = $("fbURLEncodeValue", this.window);
 57 
 58         // Fix for issue 39: decode cookie name and value for usage in the dialog.
 59         // It'll be encoded again when OK is pressed.
 60         // Don't escape using encodeURIComponent sinc "+" would be changed, but 
 61         // it's valid replacement for space.
 62         // This is also necessary for issue 45.
 63         this.nameNode.value = unescape(this.cookie.name);
 64         this.valueNode.value = unescape(this.cookie.rawValue);
 65 
 66         this.domainNode.value = this.cookie.host;
 67         this.pathNode.value = this.cookie.path;
 68         this.secureNode.checked = this.cookie.isSecure;
 69         this.httpOnly.checked = this.cookie.isHttpOnly;
 70         this.URLEncodeValue.checked = this.cookie.rawValue != unescape(this.cookie.rawValue);
 71 
 72         if (this.cookie.expires)
 73         {
 74             var expires = new Date(this.cookie.expires * 1000);
 75             this.expireNode.value = expires.toGMTString();
 76         }
 77         else
 78         {
 79             this.sessionNode.checked = true;
 80 
 81             // Set default value for expire time (current time + some time, see prefs 
 82             // defaultInterval) so, the cookie doesn't disappear if the session box 
 83             // is just unchecked.
 84 
 85             // xxxHonza: the default time is always set to the current time.
 86             //if (!this.expireNode.value)
 87             {
 88                 var expireTime = Firebug.CookieModule.getDefaultCookieExpireTime();
 89                 var expires = new Date(expireTime * 1000);
 90                 this.expireNode.value = expires.toGMTString();
 91             }
 92         }
 93 
 94         // Update expire date-time picker.
 95         this.onSession();
 96 
 97         // Translate all string in the UI.
 98         this.fcInternationalizeUI();
 99     },
100 
101     fcInternationalizeUI: function()
102     {
103         var elements = ["fcEditCookieDlg", "fcNameLabel", "fcIsDomainLabel", "fcPathLabel",
104             "fcExpireLabel", "fcSession", "fcValueLabel", "fcSecure", "fcHttpOnly",
105             "fbURLEncodeValue"];
106 
107         for (var i=0; i<elements.length; i++)
108         {
109             var element = $(elements[i], this.window);
110             if (element.hasAttribute("title"))
111                 Locale.internationalize(element, "title");
112 
113             if (element.hasAttribute("label"))
114                 Locale.internationalize(element, "label");
115 
116             if (element.hasAttribute("value"))
117                 Locale.internationalize(element, "value");
118         }
119     },
120 
121     onOK: function()
122     {
123         if (!this.checkValues())
124             return false;
125 
126         var isSession = this.sessionNode.checked;
127         var host = this.domainNode.value;
128 
129         var cookieName = this.nameNode.value;
130         var cookieValue = this.valueNode.value;
131 
132         // Fix for issue 39: Can't create cookies with ';' in the name
133         // But do not escape all,see issue 60: "[" and "]" characters get badly encoded
134         // on cookie name upon editing
135         cookieName = cookieName.replace(/\;/g, "%3B");
136 
137         // According to the spec cookie value must be escaped
138         if (this.URLEncodeValue.checked)
139             cookieValue = escape(cookieValue);
140 
141         // Issue 45: When I copy and paste or edit a cookie contents + (plus) signs
142         // get converted to spaces.
143         cookieValue = cookieValue.replace(/\+/g, "%2B");
144 
145         // Create a helper cookie object from the provided data.
146         var values = {
147             name: cookieName,
148             rawValue: cookieValue,
149             path: this.pathNode.value,
150             host: host,
151             isSecure: this.secureNode.checked,
152             isHttpOnly: this.httpOnly.checked,
153             isDomain: (host.charAt(0) == "."),
154             expires: null // is computed below
155         };
156 
157         // will be immediately removed.
158         if (!isSession)
159         {
160             // If it isn't a session cookie set the proper expire time.
161             var expires = new Date();
162             expires.setTime(Date.parse(this.expireNode.value));
163             values.expires = Math.floor(expires.valueOf() / 1000);
164         }
165 
166         // Create/modify cookie.
167         var cookie = new Cookie(values);
168         Firebug.CookieModule.createCookie(cookie);
169 
170         // Close dialog.
171         this.window.close();
172 
173         return true;
174     },
175 
176     /**
177      * Verify values before the OK button is pressed.
178      */
179     checkValues: function()
180     {
181         var name = this.nameNode.value;
182         if (!name)
183         {
184             prompts.alert(this.window, Locale.$STR("Firebug"),
185                 Locale.$STR("cookies.edit.invalidname"));
186             return false;
187         }
188 
189         var domain = this.domainNode.value;
190         if (!this.checkHost(domain))
191         {
192             prompts.alert(this.window, Locale.$STR("Firebug"),
193                 Locale.$STR("cookies.edit.invalidhost"));
194             return false;
195         }
196 
197         var path = this.pathNode.value;
198         if (!this.checkPath(domain, path))
199         {
200             prompts.alert(this.window, Locale.$STR("Firebug"),
201                 Locale.$STR("cookies.edit.invalidpath"));
202             return false;
203         }
204 
205         return true;
206     },
207 
208     onCancel: function()
209     {
210         window.close();
211     },
212 
213     onSession: function()
214     {
215         this.expireNode.disabled = this.sessionNode.checked;
216     },
217 
218     checkHost: function(host)
219     {
220         if (!host)
221             return false;
222 
223         try 
224         {
225             var uri = "http://" + host + "/";
226             return ioService.newURI(uri, null, null) ? true : false;
227         }
228         catch (err) {
229         }
230 
231         return false;
232     },
233 
234     checkPath: function(host, path)
235     {
236         if (!path)
237             return false;
238 
239         try {
240             var uri = "http://" + host + "/" + path;
241             return ioService.newURI(uri, null, null) ? true : false;
242         } 
243         catch(err) {
244         }
245 
246         return false;
247     },
248 
249     createDateTimeField: function()
250     {
251         // Get the box element where the dateTime field should be located.
252         var expireBox = this.window.document.getElementById("fcExpireBox");
253 
254         var dateTimeField = null;
255         if (versionChecker.compare(appInfo.version, "3.0*") >= 0)
256         {
257             // Use new <datepicker> and <timepicker> XUL elements (introduced in Firefox 3)
258             dateTimeField = this.window.document.createElement("dateTimePicker");
259         }
260         else
261         {
262             // Use simple text field with GMT time format.
263             dateTimeField = this.window.document.createElement("textbox");
264             dateTimeField.setAttribute("cols", "12");
265             dateTimeField.setAttribute("flex", "1");
266         }
267 
268         // Append it into the UI.
269         dateTimeField.id = "fcExpire";
270         expireBox.appendChild(dateTimeField);
271     },
272 
273     getChromeWindow: function()
274     {
275         return windowMediator.getMostRecentWindow("navigator:browser");
276     }
277 }
278 
279 // ********************************************************************************************* //
280 // Helpers
281 
282 function $(id, win)
283 {
284     return win.document.getElementById(id);
285 }
286 
287 // ********************************************************************************************* //
288 // Registration
289 
290 return EditCookie;
291 
292 // ********************************************************************************************* //
293 });
294