Attachment #387569: CSP Work in Progress (v3.6) for bug #493857

View | Details | Raw Unified | Return to bug 493857
Collapse All | Expand All

(-)f46e6aee1335 (+107 lines)
Added Link Here 
Added Link Here 
1
/* ***** BEGIN LICENSE BLOCK *****
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3
 *
4
 * The contents of this file are subject to the Mozilla Public License Version
5
 * 1.1 (the "License"); you may not use this file except in compliance with
6
 * the License. You may obtain a copy of the License at
7
 * http://www.mozilla.org/MPL/
8
 *
9
 * Software distributed under the License is distributed on an "AS IS" basis,
10
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
 * for the specific language governing rights and limitations under the
12
 * License.
13
 *
14
 * The Original Code is the nsCSPContentPolicy service.
15
 *
16
 * The Initial Developer of the Original Code is
17
 *   Sid Stamm <sid@mozilla.com>
18
 *
19
 * Contributor(s):
20
 *   Brandon Sterne <bsterne@mozilla.com>
21
 *
22
 * Alternatively, the contents of this file may be used under the terms of
23
 * either the GNU General Public License Version 2 or later (the "GPL"), or
24
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25
 * in which case the provisions of the GPL or the LGPL are applicable instead
26
 * of those above. If you wish to allow use of your version of this file only
27
 * under the terms of either the GPL or the LGPL, and not to allow others to
28
 * use your version of this file under the terms of the MPL, indicate your
29
 * decision by deleting the provisions above and replace them with the notice
30
 * and other provisions required by the GPL or the LGPL. If you do not delete
31
 * the provisions above, a recipient may use your version of this file under
32
 * the terms of any one of the MPL, the GPL or the LGPL.
33
 *
34
 * ***** END LICENSE BLOCK ***** */
35
36
#include "nsISupports.idl"
37
#include "nsIURI.idl"
38
#include "nsIHttpChannel.idl"
39
#include "nsIDocShell.idl"
40
41
/**
42
 * IContentSecurityPolicy  
43
 * Describes an XPCOM component used to model an enforce CSPs.
44
 */
45
46
[scriptable, uuid(AB36A2BF-CB32-4AA6-AB41-6B4E4444A221)]
47
interface IContentSecurityPolicy : nsISupports
48
{
49
50
  /**
51
   * Set to true when the CSP has been read in and parsed and is ready to
52
   * enforce.  This is a barrier for the nsDocument so it doesn't load any
53
   * sub-content until either it knows that a CSP is ready or will not be used.
54
   */
55
  attribute boolean isInitialized;
56
57
  /**
58
   * A read-only string version of the policy for debugging.
59
   */
60
  readonly attribute AString policy;
61
62
  /**
63
   * Called after the CSP object is created to fill in the appropriate request
64
   * and request header information needed in case a report needs to be sent.
65
   */
66
  void scanRequestData(in nsIHttpChannel aChannel);
67
68
  /**
69
   * Updates the policy currently stored in the CSP to be "refined" or
70
   * tightened by the one specified in the string policyString.
71
   */
72
  void refinePolicy(in AString policyString, in nsIURI selfURI);
73
74
  /**
75
   * Verifies ancestry as permitted by the policy.
76
   * @param docShell
77
   *    containing the protected resource
78
   * @return
79
   *    true if the frame's ancestors are all permitted by policy
80
   */
81
  boolean permitsAncestry(in nsIDocShell docShell);
82
83
  /**
84
   * Delegate method called by the service when sub-elements of the protected
85
   * document are being loaded.  Given a bit of information about the request,
86
   * decides whether or not the policy is satisfied.
87
   */
88
  short shouldLoad(in unsigned long   aContentType, 
89
                   in nsIURI          aContentLocation, 
90
                   in nsIURI          aRequestOrigin, 
91
                   in nsISupports     aContext, 
92
                   in ACString        aMimeTypeGuess, 
93
                   in nsISupports     aExtra);
94
95
  /**
96
   * Delegate method called by the service when sub-elements of the protected
97
   * document are being processed.  Given a bit of information about the request,
98
   * decides whether or not the policy is satisfied.
99
   */
100
  short shouldProcess(in unsigned long   aContentType, 
101
                      in nsIURI          aContentLocation, 
102
                      in nsIURI          aRequestOrigin, 
103
                      in nsISupports     aContext, 
104
                      in ACString        aMimeType,
105
                      in nsISupports     aExtra);
106
107
};
(-)a/caps/idl/Makefile.in (+1 lines)
Line     Link Here 
 Lines 45-56   include $(DEPTH)/config/autoconf.mk Link Here 
45
MODULE		= caps
45
MODULE		= caps
46
GRE_MODULE	= 1
46
GRE_MODULE	= 1
47
47
48
XPIDLSRCS	= \
48
XPIDLSRCS	= \
49
		nsIScriptSecurityManager.idl \
49
		nsIScriptSecurityManager.idl \
50
		nsIPrincipal.idl \
50
		nsIPrincipal.idl \
51
		nsISignatureVerifier.idl \
51
		nsISignatureVerifier.idl \
52
		nsISecurityCheckedComponent.idl \
52
		nsISecurityCheckedComponent.idl \
53
		IContentSecurityPolicy.idl \
53
		$(NULL)
54
		$(NULL)
54
55
55
include $(topsrcdir)/config/rules.mk
56
include $(topsrcdir)/config/rules.mk
56
57
(-)f46e6aee1335 (+932 lines)
Added Link Here 
Added Link Here 
1
/* ***** BEGIN LICENSE BLOCK *****
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3
 *
4
 * The contents of this file are subject to the Mozilla Public License Version
5
 * 1.1 (the "License"); you may not use this file except in compliance with
6
 * the License. You may obtain a copy of the License at
7
 * http://www.mozilla.org/MPL/
8
 *
9
 * Software distributed under the License is distributed on an "AS IS" basis,
10
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
 * for the specific language governing rights and limitations under the
12
 * License.
13
 *
14
 * The Original Code is the Content Security Policy data structures.
15
 *
16
 * The Initial Developer of the Original Code is
17
 * Sid Stamm <sid@mozilla.com>
18
 *
19
 * Contributor(s):
20
 *
21
 * Alternatively, the contents of this file may be used under the terms of
22
 * either the GNU General Public License Version 2 or later (the "GPL"), or
23
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
24
 * in which case the provisions of the GPL or the LGPL are applicable instead
25
 * of those above. If you wish to allow use of your version of this file only
26
 * under the terms of either the GPL or the LGPL, and not to allow others to
27
 * use your version of this file under the terms of the MPL, indicate your
28
 * decision by deleting the provisions above and replace them with the notice
29
 * and other provisions required by the GPL or the LGPL. If you do not delete
30
 * the provisions above, a recipient may use your version of this file under
31
 * the terms of any one of the MPL, the GPL or the LGPL.
32
 *
33
 * ***** END LICENSE BLOCK ***** */
34
35
/**
36
 * Content Security Policy Utilities
37
 * 
38
 * Overview
39
 * This contains a set of classes and utilities for CSP.  It is in this
40
 * separate file for testing purposes.
41
 */
42
43
// Module stuff
44
var EXPORTED_SYMBOLS = ["CSPRep", "CSPSourceList", "CSPSource", 
45
                        "CSPHost", "CSPWarning", "CSPError", "CSPdebug"];
46
47
function CSPWarning(aMsg) {
48
  //customize this to redirect output.
49
  aMsg = 'CSP WARN:  ' + aMsg + "\n";
50
  dump(aMsg);
51
  Components.classes["@mozilla.org/consoleservice;1"]
52
                    .getService(Components.interfaces.nsIConsoleService)
53
                    .logStringMessage(aMsg);
54
}
55
function CSPError(aMsg) {
56
  aMsg = 'CSP ERROR: ' + aMsg + "\n";
57
  dump(aMsg);
58
  Components.classes["@mozilla.org/consoleservice;1"]
59
                    .getService(Components.interfaces.nsIConsoleService)
60
                    .logStringMessage(aMsg);
61
}
62
function CSPdebug(aMsg) {
63
  aMsg = 'CSP debug: ' + aMsg + "\n";
64
  dump(aMsg);
65
  Components.classes["@mozilla.org/consoleservice;1"]
66
                    .getService(Components.interfaces.nsIConsoleService)
67
                    .logStringMessage(aMsg);
68
}
69
70
71
//:::::::::::::::::::::::: CLASSES ::::::::::::::::::::::::::// 
72
73
/**
74
 * Class that represents a parsed policy structure.
75
 */
76
function CSPRep() {
77
  // this gets set to true when the policy is done parsing, or when a
78
  // URI-borne policy has finished loading.
79
  this._isInitialized = false;
80
81
  this._allowEval = false;
82
  this._allowInlineScripts = false;
83
84
  // don't auto-populate _directives, so it is easier to find bugs
85
  this._directives = {};
86
87
}
88
CSPRep.SRC_DIRECTIVES = {
89
  ALLOW:            "allow",
90
  SCRIPT_SRC:       "script-src",
91
  STYLE_SRC:        "style-src",
92
  MEDIA_SRC:        "media-src",
93
  IMG_SRC:          "img-src",
94
  OBJECT_SRC:       "object-src",
95
  FRAME_SRC:        "frame-src",
96
  FRAME_ANCESTORS:  "frame-ancestors"
97
};
98
CSPRep.URI_DIRECTIVES = {
99
  REPORT_URI:       "report-uri",
100
  POLICY_URI:       "policy-uri"
101
};
102
103
104
/**
105
  * Factory to create a new CSPRep, parsed from a string.
106
  *
107
  * @param aStr
108
  *        string rep of a CSP
109
  * @param self (optional)
110
  *        string or CSPSource representing the "self" source
111
  * @returns
112
  *        an instance of CSPRep
113
  */
114
CSPRep.fromString = function(aStr, self) {
115
  var SD = CSPRep.SRC_DIRECTIVES;
116
  var UD = CSPRep.URI_DIRECTIVES;
117
  var pieces = aStr.split(/;\s*/);
118
  var aCSPR = new CSPRep();
119
  piece:for(var i in pieces) {
120
    //split off first token and figure out what to do
121
    var dirname = pieces[i].match(/(\S+)/)[0];
122
123
    //careful to trim the stuff so there's no extra tokens 
124
    var dirvalue = pieces[i].substring(dirname.length)
125
                            .replace(/^\s+/,'')
126
                            .replace(/\s+$/,'');
127
128
    //If it is the script-src directive, pull out "eval" and "inline"
129
    if(dirname == SD.STYLE_SRC) {
130
      let listchunks = dirvalue.split(/\s+/);
131
      for(let i in listchunks) {
132
        if(listchunks[i] == "eval") {
133
          listchunks.splice(i,1);
134
          aCSPR._allowEval = true;
135
        }
136
        if(listchunks[i] == "inline") {
137
          listchunks.splice(i,1);
138
          aCSPR._allowInlineScripts = true;
139
        }
140
      }
141
      // repair source list without the keywords
142
      dirvalue = listchunks.join(" ");
143
    }
144
145
    //is it a SRC directive?
146
    for(var sdi in SD) {
147
      if(dirname == SD[sdi]) {
148
        var dv = CSPSourceList.fromString(dirvalue, self);
149
        //TODO: more robust check for errors in making DV
150
        aCSPR._directives[SD[sdi]] = dv;
151
        continue piece;
152
      }
153
    }
154
155
    //not a SRC directive, check URI directives
156
    if(dirname == UD.POLICY_URI) {
157
      // POLICY_URI can only be alone
158
      if(aCSPR._directives.length > 0 || pieces.length > 1) {
159
        CSPError("policy-uri directive can only appear alone");
160
        return CSPRep.fromString("allow none");
161
      }
162
163
      //return;
164
      //TODO: verify that policy URI is same-origin
165
      var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]  
166
                  .createInstance(Components.interfaces.nsIXMLHttpRequest);  
167
168
      // insert error hook
169
      req.onerror = CSPError;
170
171
      // synchronous -- otherwise we need to architect a callback into the
172
      // xpcom component so that whomever creates the policy object gets
173
      // notified when it's loaded and ready to go.
174
      req.open("GET", dirvalue, false);
175
176
      // make request anonymous
177
      // This prevents sending cookies with the request, in case the policy URI
178
      // is injected, it can't be abused for CSRF.
179
      req.channel.loadFlags |= Components.interfaces.nsIChannel.LOAD_ANONYMOUS;
180
181
      //CSPdebug("Fetching URI " + dirvalue);
182
      req.send(null);  
183
      if(req.status == 200) {
184
        //CSPdebug("XHR returned: " + req.responseText);
185
        aCSPR = CSPRep.fromString(req.responseText, self);
186
        //remember where we got the policy
187
        aCSPR._directives[UD.POLICY_URI] = dirvalue;
188
        return aCSPR;
189
      }
190
      CSPError("Error fetching policy URI: server response was " + req.status);
191
      return CSPRep.fromString("allow none");
192
    }
193
    if(dirname == UD.REPORT_URI) {
194
      //TODO: do we want to support multiple URIs?
195
      //TODO: verify that report URI(s) is(are) same-origin
196
      aCSPR._directives[UD.REPORT_URI] = dirvalue;
197
      continue piece;
198
    }
199
200
    //no directives matched
201
    CSPWarning("Couldn't process unknown directive '" + dirname + "'");
202
  }
203
204
  if(aCSPR._directives.length < 1) {
205
    CSPError("invalid policy -- no recognized directives");
206
    return CSPRep.fromString("allow none");
207
  }
208
209
  if(!aCSPR._directives[SD.ALLOW]) {
210
    CSPWarning("allow directive is not present, using 'allow none'");
211
    aCSPR._directives[SD.ALLOW] = CSPSourceList.fromString("none");
212
  }
213
214
  aCSPR.makeExplicit();
215
  return aCSPR;
216
};
217
218
CSPRep.prototype = {
219
  /**
220
   * Returns array of all report uris defined, or none if there are none.
221
   */
222
  getReportURIs:
223
  function() {
224
    if(!this._directives[CSPRep.URI_DIRECTIVES.REPORT_URI])
225
      return [];
226
227
    var uris = this._directives[CSPRep.URI_DIRECTIVES.REPORT_URI].split(",");
228
    for(let i in uris) {
229
      //trim off surrounding whitespace
230
      uris[i] = uris[i].replace(/^\s+/, "").replace(/\s+$/, "");
231
    }
232
    return uris;
233
  },
234
235
  /**
236
   * Compares this CSPRep instance to another.
237
   */
238
  equals:
239
  function(that) {
240
    if(this._directives.length != that._directives.length) {
241
      return false;
242
    }
243
    for(var i in this._directives) {
244
      if(!that._directives[i] || !this._directives[i].equals(that._directives[i])) {
245
        return false;
246
      }
247
    }
248
    return true;
249
  },
250
251
  /**
252
   * Generates string representation of the policy.  Should be fairly similar
253
   * to the original.
254
   */
255
  toString:
256
  function csp_toString() {
257
    var dirs = [];
258
    for(var i in this._directives) {
259
      if(this._directives[i]) {
260
        dirs.push(i + " " + this._directives[i].toString());
261
      }
262
    }
263
    return dirs.join("; ");
264
  },
265
266
267
  /**
268
   * Determines if this directive accepts a URI.
269
   * @param aContext
270
   *        one of the SRC_DIRECTIVES defined above
271
   * @returns 
272
   *        true if the policy permits the URI in given context.
273
   */
274
  permits:
275
  function csp_permits(aURI, aContext) {
276
    //make sure the context is valid
277
    for(var i in CSPRep.SRC_DIRECTIVES) {
278
      if(CSPRep.SRC_DIRECTIVES[i] == aContext) {
279
        return this._directives[aContext].permits(aURI);
280
      }
281
    }
282
    return false;
283
  },
284
285
  /**
286
   * Intersects with another CSPRep, deciding the subset policy 
287
   * that should be enforced, and returning a new instance.
288
   * @param aCSPRep
289
   *        a CSPRep instance to use as "other" CSP
290
   * @returns
291
   *        a new CSPRep instance of the intersection
292
   */
293
  intersectWith:
294
  function cspsd_intersectWith(aCSPRep) {
295
    var newRep = new CSPRep();
296
297
    for(var dir in CSPRep.SRC_DIRECTIVES) {
298
      var dirv = CSPRep.SRC_DIRECTIVES[dir];
299
      newRep._directives[dirv] = this._directives[dirv]
300
               .intersectWith(aCSPRep._directives[dirv]);
301
    }
302
    return newRep;
303
  },
304
305
306
  /**
307
   * Copies default source list to each unspecified directive.
308
   * @returns
309
   *      true  if the makeExplicit succeeds
310
   *      false if it fails (for some weird reason)
311
   */
312
  makeExplicit:
313
  function cspsd_makeExplicit() {
314
    var SD = CSPRep.SRC_DIRECTIVES;
315
    var allowDir = this._directives[SD.ALLOW];
316
    if(!allowDir) {
317
      return false;
318
    }
319
320
    for(var dir in SD) {
321
      var dirv = SD[dir];
322
      if(dirv == SD.ALLOW) {
323
        continue;
324
      }
325
      if(!this._directives[dirv]) {
326
        //implicit directive, make explicit
327
        this._directives[dirv] = allowDir.clone();
328
      }
329
    }
330
    this._isInitialized = true;
331
    return true;
332
  },
333
334
  /**
335
   * Returns true if "eval" is enabled through the "eval" keyword.
336
   */
337
  get allowsEvalInScripts () {
338
    return this._allowEval;
339
  },
340
341
  /**
342
   * Returns true if inline scripts are enabled through the "inline"
343
   * keyword.
344
   */
345
  get allowsInlineScripts () {
346
    return this._allowInlineScripts;
347
  },
348
};
349
350
351
//////////////////////////////////////////////////////////////////////
352
/**
353
 * Class to represent a list of sources 
354
 */
355
function CSPSourceList() {
356
  this._sources = [];
357
  this._permitAllSources = false;
358
}
359
360
/**
361
 * Factory to create a new CSPSourceList, parsed from a string.
362
 *
363
 * @param aStr
364
 *        string rep of a CSP Source List
365
 * @param self (optional)
366
 *        string or CSPSource representing the "self" source
367
 * @returns
368
 *        an instance of CSPSourceList 
369
 */
370
CSPSourceList.fromString = function(aStr, self) {
371
  //Source list is:
372
  //    <host-dir-value> ::= <source-list>
373
  //                       | "none"
374
  //    <source-list>    ::= <source>
375
  //                       | <source-list>" "<source>
376
377
  var slObj = new CSPSourceList();
378
  if(aStr == "none") {
379
    return slObj;
380
  }
381
382
  var ss = aStr.split(/\s+/);
383
  for(var i in ss) {
384
    var o = CSPSource.fromString(ss[i], self);
385
    //make sure none came back undefined
386
    if(!o) { return null; }
387
    slObj._sources[i] = o;
388
  }
389
  return slObj;
390
};
391
392
CSPSourceList.prototype = {
393
394
  /**
395
   * Compares one CSPSourceList to another.
396
   *
397
   * @param that
398
   *        another CSPSourceList
399
   * @returns 
400
   *        true if they have the same data
401
   */
402
  equals:
403
  function(that) {
404
    if(that._sources.length != this._sources.length) {
405
      return false;
406
    }
407
    //sort both arrays and compare like a zipper
408
    //XXX (sid): I think we can make this more efficient
409
    var sortfn = function(a,b) {
410
      return a.toString() > b.toString();
411
    };
412
    var a_sorted = this._sources.sort(sortfn);
413
    var b_sorted = that._sources.sort(sortfn);
414
    for(var i in a_sorted) {
415
      if(!a_sorted[i].equals(b_sorted[i])) {
416
        return false;
417
      }
418
    }
419
    return true;
420
  },
421
422
  /**
423
   * Generates string representation of the Source List.
424
   * Should be fairly similar to the original.
425
   */
426
  toString:
427
  function() {
428
    if(this.isNone()) {
429
      return "none";
430
    }
431
    return this._sources.map(function(x) { return x.toString(); }).join(" ");
432
  },
433
434
  /**
435
   * Returns whether or not this source list represents the "none" special
436
   * case.
437
   */
438
  isNone:
439
  function() {
440
    return (!this._permitAllSources) && (this._sources.length < 1);
441
  },
442
443
  /**
444
   * Makes a new instance that resembles this object.
445
   * @returns
446
   *      a new CSPSourceList
447
   */
448
  clone:
449
  function() {
450
    var aSL = new CSPSourceList();
451
    aSL._permitAllSources = this._permitAllSources;
452
    for(var i in this._sources) {
453
      aSL._sources[i] = this._sources[i].clone();
454
    }
455
    return aSL;
456
  },
457
458
459
  /**
460
   * Determines if this directive accepts a URI.
461
   * @param aURI
462
   *        the URI in question
463
   * @returns
464
   *        true if the URI matches a source in this source list.
465
   */
466
  permits:
467
  function cspsd_permits(aURI) {
468
    if(this.isNone()) {
469
      return false;
470
    }
471
    for(var i in this._sources) {
472
      if(this._sources[i].permits(aURI)) {
473
        return true;
474
      }
475
    }
476
    return false;
477
  },
478
479
480
  /**
481
   * Intersects with another CSPSourceList, deciding the subset directive
482
   * that should be enforced, and returning a new instance.
483
   * @param that 
484
   *        the other CSPSourceList to intersect "this" with
485
   * @returns
486
   *        a new instance of a CSPSourceList representing the intersection
487
   */
488
  intersectWith:
489
  function cspsd_intersectWith(that) {
490
    if(this._permitAllSources) {
491
      return that.clone();
492
    }
493
    if(that._permitAllSources) {
494
      return this.clone();
495
    }
496
497
    // "none" case
498
    if(this.isNone() || that.isNone()) {
499
      return CSPSourceList.fromString("none");
500
    }
501
502
    // --  find only common sources
503
504
    //XXX (sid): figure out a good algorithm for this.
505
    // This is horribly inefficient. O(n^2)
506
    var isrcs = [];
507
    for(var i in this._sources) {
508
      for(var j in that._sources) {
509
        var s = that._sources[j].intersectWith(this._sources[i]);
510
        if(s) {
511
          isrcs.push(s);
512
        }
513
      }
514
    }
515
    //Next, remove duplicates
516
    dup:for(var i = 0; i < isrcs.length; i++) {
517
      for(var j = 0; j < i; j++) {
518
        if(isrcs[i].equals(isrcs[j])) {
519
          isrcs.splice(i, 1);
520
          i--;
521
          continue dup;
522
        }
523
      }
524
    }
525
    var newCSPSrcList = new CSPSourceList();
526
    newCSPSrcList._sources = isrcs;
527
    return newCSPSrcList;
528
  }
529
}
530
531
532
//////////////////////////////////////////////////////////////////////
533
/**
534
 * Class to model a source (scheme, host, port)
535
 */
536
function CSPSource() {
537
  this._scheme = "*";
538
  this._port = "*";
539
  this._host = "*";
540
}
541
542
CSPSource._PORT_RE = /(:(\*|\d+))$/;
543
CSPSource._SCHM_RE = /^((\*|[a-zA-Z][a-zA-Z\+\.\-]*):\/{0,2})/;
544
CSPSource._HOST_RE = /^(localhost|\*|(((\*|[a-zA-Z0-9\-]+)\.)([a-zA-Z0-9\-]+\.)*([a-zA-Z0-9\-]+)))$/;
545
546
/**
547
 * Factory to create a new CSPSource, from a nsIURI.
548
 *
549
 * @param aURI
550
 *        nsIURI rep of a URI
551
 * @param self (optional)
552
 *        string or CSPSource representing the "self" source
553
 * @returns
554
 *        an instance of CSPSource 
555
 */
556
CSPSource.fromURI = function(aURI, self) {
557
558
  if( !(aURI instanceof Components.interfaces.nsIURI) ){
559
    CSPError("Provided argument is not an nsIURI");
560
    return null;
561
  }
562
563
  var sObj = new CSPSource();
564
565
  try { // try block in case there's no host specified in the URI
566
    if(!aURI.host)
567
      sObj._host = "*";
568
    else
569
      sObj._host = aURI.host;
570
  } catch(e) {}
571
572
  // Don't forget to handle "self" tokens in the URI
573
  if(sObj._host == "self") {
574
    if(!self) {
575
      CSPError("self keyword used, but no self data specified");
576
      return null;
577
    } 
578
    if(self == "self") {
579
      CSPError("self reference cannot be 'self'");
580
      return null;
581
    }
582
    if(!(self instanceof CSPSource)) { 
583
      self = CSPSource.fromString(self);
584
    }
585
    sObj._host = self._host;
586
    if(!sObj._port) {
587
      sObj._port = self._port;
588
    }
589
  }
590
591
  try { // it's possible there's not an available port
592
    if(aURI.port)
593
      sObj._port = aURI.port;
594
    else
595
      sObj._port = (self ? self._port : "*");
596
  } catch(e) {}
597
598
  if(aURI.scheme)
599
    sObj._scheme = aURI.scheme;
600
  else
601
    sObj._scheme = (self ? self._scheme : "*");
602
603
  return sObj;
604
};
605
606
/**
607
 * Factory to create a new CSPSource, parsed from a string.
608
 *
609
 * @param aStr
610
 *        string rep of a CSP Source
611
 * @param self (optional)
612
 *        string or CSPSource representing the "self" source
613
 * @returns
614
 *        an instance of CSPSource 
615
 */
616
CSPSource.fromString = function(aStr, self) {
617
  if(aStr == "self") {
618
    if(!self) {
619
      CSPError("self keyword used, but no self data specified");
620
      return null;
621
    } 
622
    if(self == "self") {
623
      CSPError("self reference cannot be 'self'");
624
      return null;
625
    }
626
    if(self instanceof CSPSource) { 
627
      return self.clone();
628
    }
629
    return CSPSource.fromString(self);
630
  }
631
632
  var s = aStr;
633
  var sObj = new CSPSource();
634
635
  if(self && !(self instanceof CSPSource)) {
636
    self = CSPSource.fromString(self);
637
  }
638
639
  // IMPORTANT: scan for port first, because host can be mistaken for scheme
640
  // due to the allowance of dots in the scheme (and a colon before the port)
641
  if(CSPSource._PORT_RE.test(s)) {
642
    sObj._port = s.match(CSPSource._PORT_RE)[0].replace(/:/,'');
643
    s = s.replace(CSPSource._PORT_RE, '');
644
  } else if(self) {
645
    sObj._port = self._port;
646
  }
647
648
  if(CSPSource._SCHM_RE.test(s)) {
649
    sObj._scheme = s.match(CSPSource._SCHM_RE)[0].replace(/[:\/]+/,'');
650
    s = s.replace(CSPSource._SCHM_RE, '');
651
  } else if(self) {
652
    sObj._scheme = self._scheme;
653
  }
654
655
  
656
  if(CSPSource._HOST_RE.test(s)) {
657
    sObj._host = CSPHost.fromString(s.match(CSPSource._HOST_RE)[0]);
658
    if(sObj._host) {
659
      return sObj;
660
    }
661
  } 
662
  CSPError("failed parsing host: '" + s + "'");
663
  return null;
664
};
665
666
CSPSource.prototype = {
667
668
  /**
669
   * Generates string representation of the Source.
670
   * Should be fairly similar to the original.
671
   */
672
  toString:
673
  function() {
674
    var s = this._host;
675
    if(this._port && this._port != "*") {
676
      s = s + ":" + this._port;
677
    }
678
    if(this._scheme && this._scheme != "*") {
679
      s = this._scheme + "://" + s;
680
    }
681
    return s;
682
  },
683
684
  /**
685
   * Makes a new instance that resembles this object.
686
   * @returns
687
   *      a new CSPSource
688
   */
689
  clone:
690
  function() {
691
    var aClone = new CSPSource();
692
    aClone._scheme = this._scheme;
693
    aClone._port = this._port;
694
    aClone._host = this._host.clone();
695
    return aClone;
696
  },
697
698
  /**
699
   * Determines if this Source accepts a URI.
700
   * @param aURI
701
   *        the URI in question
702
   * @returns
703
   *        true if the URI matches a source in this source list.
704
   */
705
  permits:
706
  function(aSource) {
707
    if(aSource instanceof Components.interfaces.nsIURI) {
708
      //figure out based on URI
709
      return this.permits(CSPSource.fromURI(aSource));
710
    }
711
    if(!(aSource instanceof CSPSource)) {
712
      //convert to CSPSource first
713
      return this.permits(CSPSource.fromString(aSource));
714
    }
715
716
    //verify scheme, host, and port
717
    if(    (this._scheme == "*" || this._scheme == aSource._scheme)
718
        && (this._port == "*"   || this._port == aSource._port)    ){
719
      return this._host.permits(aSource._host);
720
    }
721
    // something didn't match.
722
    return false;
723
  },
724
725
  /**
726
   * Determines the intersection of two sources.
727
   * Returns a null object if intersection generates no
728
   * hosts that satisfy it.
729
   * @param that 
730
   *        the other CSPSource to intersect "this" with
731
   * @returns
732
   *        a new instance of a CSPSource representing the intersection
733
   */
734
  intersectWith:
735
  function(that) {
736
    var newSource = new CSPSource();
737
738
    //port
739
    if(this._port == "*") { 
740
      newSource._port = that._port;
741
    } else if(that._port == "*") { 
742
      newSource._port = this._port;
743
    } else if(that._port == this._port) {
744
      newSource._port = this._port;
745
    } else {
746
      //CSPError("Could not intersect " + this + " with " + that
747
      //         + " due to port problems.");
748
      return null;
749
    }
750
751
    //scheme
752
    if(this._scheme == "*") { 
753
      newSource._scheme = that._scheme;
754
    } else if(that._scheme == "*") { 
755
      newSource._scheme = this._scheme;
756
    } else if(that._scheme == this._scheme) {
757
      newSource._scheme = this._scheme;
758
    } else {
759
      //CSPError("Could not intersect " + this + " with " + that
760
      //         + " due to scheme problems.");
761
      return null;
762
    }
763
764
    //host
765
    newSource._host = this._host.intersectWith(that._host);
766
767
    return newSource._host ? newSource : null;
768
  },
769
770
  /**
771
   * Compares one CSPSource to another.
772
   *
773
   * @param that
774
   *        another CSPSource
775
   * @returns 
776
   *        true if they have the same data
777
   */
778
  equals:
779
  function(aSrc) {
780
    return this._scheme == aSrc._scheme
781
        && this._port == aSrc._port
782
        && this._host.equals(aSrc._host);
783
  }
784
};
785
  
786
787
//////////////////////////////////////////////////////////////////////
788
/**
789
 * Class to model a host *.x.y.
790
 */
791
function CSPHost() {
792
  this._segments = [];
793
}
794
795
/**
796
 * Factory to create a new CSPHost, parsed from a string.
797
 *
798
 * @param aStr
799
 *        string rep of a CSP Host 
800
 * @returns
801
 *        an instance of CSPHost
802
 */
803
CSPHost.fromString = function(aStr) {
804
  var hObj = new CSPHost();
805
  hObj._segments = aStr.split(/\./);
806
  if(hObj._segments.length < 1 ||
807
     hObj._segments.length == 1 && hObj._segments[0] != "*"
808
                                && hObj._segments[0] != "localhost") {
809
    //only short hosts allowed are "*" and "localhost"
810
    return null;
811
  }
812
  //TODO: double-check that each segment is appropriate.
813
  return hObj;
814
};
815
816
CSPHost.prototype = {
817
  /**
818
   * Generates string representation of the Source.
819
   * Should be fairly similar to the original.
820
   */
821
  toString:
822
  function() {
823
    return this._segments.join(".");
824
  },
825
826
  /**
827
   * Makes a new instance that resembles this object.
828
   * @returns
829
   *      a new CSPHost
830
   */
831
  clone:
832
  function() {
833
    var aHost = new CSPHost();
834
    for(var i in this._segments) {
835
      aHost._segments[i] = this._segments[i];
836
    }
837
    return aHost;
838
  },
839
840
  /**
841
   * Returns true if this host accepts the provided host (or the other way
842
   * around).
843
   * @param aHost
844
   *        the FQDN in question (CSPHost or String)
845
   * @returns
846
   */
847
  permits:
848
  function(aHost) {
849
    if(!(aHost instanceof CSPHost)) {
850
      // -- compare CSPHost to String
851
      return this.permits(CSPHost.fromString(aHost));
852
    }
853
    var thislen = this._segments.length;
854
    var thatlen = aHost._segments.length;
855
856
    // don't accept a less specific host: 
857
    //   \--> *.b.a doesn't accept b.a.
858
    if(thatlen < thislen) { return false; }
859
860
    // check for more specific host (and wildcard):
861
    //   \--> *.b.a accepts d.c.b.a.
862
    //   \--> c.b.a doesn't accept d.c.b.a.
863
    if((thatlen > thislen) && this._segments[0] != "*") {
864
      return false;
865
    }
866
867
    // Given the wildcard condition (from above), 
868
    // only necessary to compare elements that are present
869
    // in this host.  Extra tokens in aHost are ok. 
870
    // * Compare from right to left.
871
    for(var i=1; i <= thislen; i++) {
872
      if( this._segments[thislen-i] != "*" && 
873
          (this._segments[thislen-i] != aHost._segments[thatlen-i]) ) {
874
        return false;
875
      }
876
    }
877
878
    //at this point, all conditions are met, so the host is allowed
879
    return true;
880
  },
881
882
  /**
883
   * Determines the intersection of two Hosts.
884
   * Basically, they must be the same, or one must have a wildcard.
885
   * @param that 
886
   *        the other CSPHost to intersect "this" with
887
   * @returns
888
   *        a new instance of a CSPHost representing the intersection
889
   *        (or null, if they can't be intersected)
890
   */
891
  intersectWith:
892
  function(that) {
893
    if(!(this.permits(that) || that.permits(this))) {
894
      // host definitions cannot co-exist without a more general host
895
      // ... one must be a subset of the other, or intersection makes no sense.
896
      return null;
897
    } 
898
899
    // pick the more specific one, if both are same length.
900
    if(this._segments.length == that._segments.length) {
901
      // *.a vs b.a : b.a
902
      return (this._segments[0] == "*") ? that.clone() : this.clone();
903
    }
904
905
    //different lengths...
906
    // *.b.a vs *.a : *.b.a
907
    // *.b.a vs d.c.b.a : d.c.b.a
908
    return (this._segments.length > that._segments.length) 
909
            ? this.clone() : that.clone();
910
  },
911
912
  /**
913
   * Compares one CSPHost to another.
914
   *
915
   * @param that
916
   *        another CSPHost
917
   * @returns 
918
   *        true if they have the same data
919
   */
920
  equals:
921
  function(that) {
922
    if(this._segments.length != that._segments.length) {
923
      return false;
924
    }
925
    for(var i=0; i<this._segments.length; i++) {
926
      if(this._segments[i] != that._segments[i]) {
927
        return false;
928
      }
929
    }
930
    return true;
931
  }
932
};
(-)a/caps/src/Makefile.in (+9 lines)
Line     Link Here 
 Lines 83-94   endif Link Here 
83
83
84
EXTRA_DSO_LDOPTS = \
84
EXTRA_DSO_LDOPTS = \
85
		$(LIBS_DIR) \
85
		$(LIBS_DIR) \
86
		$(ZLIB_LIBS) \
86
		$(ZLIB_LIBS) \
87
		$(MOZ_JS_LIBS) \
87
		$(MOZ_JS_LIBS) \
88
		$(MOZ_COMPONENT_LIBS) \
88
		$(MOZ_COMPONENT_LIBS) \
89
		$(NULL)
89
		$(NULL)
90
90
91
EXTRA_PP_COMPONENTS = \
92
		contentSecurityPolicy.js \
93
		$(NULL)
94
95
EXTRA_JS_MODULES = \
96
		CSPUtils.jsm \
97
		$(NULL)
98
99
91
include $(topsrcdir)/config/rules.mk
100
include $(topsrcdir)/config/rules.mk
92
101
93
INCLUDES	+= -I$(srcdir)/../include
102
INCLUDES	+= -I$(srcdir)/../include
94
103
(-)f46e6aee1335 (+351 lines)
Added Link Here 
Added Link Here 
1
/* ***** BEGIN LICENSE BLOCK *****
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3
 *
4
 * The contents of this file are subject to the Mozilla Public License Version
5
 * 1.1 (the "License"); you may not use this file except in compliance with
6
 * the License. You may obtain a copy of the License at
7
 * http://www.mozilla.org/MPL/
8
 *
9
 * Software distributed under the License is distributed on an "AS IS" basis,
10
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
 * for the specific language governing rights and limitations under the
12
 * License.
13
 *
14
 * The Original Code is the nsCSPContentPolicy service.
15
 *
16
 * The Initial Developer of the Original Code is
17
 * Sid Stamm <sid@mozilla.com>
18
 *
19
 * Contributor(s):
20
 *   Brandon Sterne <bsterne@mozilla.com>
21
 *
22
 * Alternatively, the contents of this file may be used under the terms of
23
 * either the GNU General Public License Version 2 or later (the "GPL"), or
24
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25
 * in which case the provisions of the GPL or the LGPL are applicable instead
26
 * of those above. If you wish to allow use of your version of this file only
27
 * under the terms of either the GPL or the LGPL, and not to allow others to
28
 * use your version of this file under the terms of the MPL, indicate your
29
 * decision by deleting the provisions above and replace them with the notice
30
 * and other provisions required by the GPL or the LGPL. If you do not delete
31
 * the provisions above, a recipient may use your version of this file under
32
 * the terms of any one of the MPL, the GPL or the LGPL.
33
 *
34
 * ***** END LICENSE BLOCK ***** */
35
36
37
/**
38
 * Content Security Policy
39
 * 
40
 * Overview
41
 * This is a stub component that will be fleshed out to do all the fancy stuff
42
 * that ContentSecurityPolicy has to do.
43
 */
44
45
/* :::::::: Constants and Helpers ::::::::::::::: */
46
47
const Cc = Components.classes;
48
const Ci = Components.interfaces;
49
const Cr = Components.results;
50
const Cu = Components.utils;
51
52
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
53
Cu.import("resource://gre/modules/CSPUtils.jsm");
54
55
/* ::::: Policy Parsing & Data structures :::::: */
56
57
function ContentSecurityPolicy() {
58
  CSPdebug("CSP CREATED");
59
  this._isInitialized = false;
60
  this._policy = CSPRep.fromString("allow *");
61
  this._requestHeaders = []; 
62
  this._request = "";
63
  CSPdebug("CSP POLICY INITED TO 'allow *'");
64
}
65
66
/*
67
 * Set up mappings from nsIContentPolicy content types to CSP directives.
68
 */
69
with(Ci.nsIContentPolicy) {
70
  let csp = ContentSecurityPolicy;
71
  let cspr_sd = CSPRep.SRC_DIRECTIVES;
72
73
  csp._MAPPINGS=[];
74
75
  /* default, catch-all case */
76
  csp._MAPPINGS[TYPE_OTHER]             =  cspr_sd.ALLOW;
77
78
  /* self */
79
  csp._MAPPINGS[TYPE_DOCUMENT]          =  null;
80
81
  /* shouldn't see this one */
82
  csp._MAPPINGS[TYPE_REFRESH]           =  null;
83
84
  /* categorized content types */
85
  csp._MAPPINGS[TYPE_SCRIPT]            = cspr_sd.SCRIPT_SRC;
86
  csp._MAPPINGS[TYPE_IMAGE]             = cspr_sd.IMG_SRC;
87
  csp._MAPPINGS[TYPE_STYLESHEET]        = cspr_sd.STYLE_SRC;
88
  csp._MAPPINGS[TYPE_OBJECT]            = cspr_sd.OBJECT_SRC;
89
  csp._MAPPINGS[TYPE_SUBDOCUMENT]       = cspr_sd.FRAME_SRC;
90
  csp._MAPPINGS[TYPE_MEDIA]             = cspr_sd.MEDIA_SRC;
91
92
93
  /* These must go through the catch-all */
94
  csp._MAPPINGS[TYPE_XBL]               = cspr_sd.ALLOW;
95
  csp._MAPPINGS[TYPE_PING]              = cspr_sd.ALLOW;
96
  csp._MAPPINGS[TYPE_XMLHTTPREQUEST]    = cspr_sd.ALLOW;
97
  csp._MAPPINGS[TYPE_OBJECT_SUBREQUEST] = cspr_sd.ALLOW;
98
  csp._MAPPINGS[TYPE_DTD]               = cspr_sd.ALLOW;
99
  csp._MAPPINGS[TYPE_FONT]              = cspr_sd.ALLOW;
100
}
101
102
ContentSecurityPolicy.prototype = {
103
  classDescription: "Content Security Policy Component",
104
  contractID:       "@mozilla.org/contentsecuritypolicy;1",
105
  classID:          Components.ID("{AB36A2BF-CB32-4AA6-AB41-6B4E4444A221}"),
106
  QueryInterface:   XPCOMUtils.generateQI([Ci.IContentSecurityPolicy]),
107
108
  // get this contractID registered for certain categories via XPCOMUtils
109
  _xpcom_categories: [ ],
110
111
  get isInitialized() {
112
    return this._isInitialized;
113
  },
114
115
  set isInitialized (foo) {
116
    this._isInitialized = foo;
117
  },
118
119
  get policy () {
120
    return this._policy.toString();
121
  },
122
123
  /*
124
  // Having a setter is a bad idea... opens up the policy to "loosening"
125
  // Instead, use "refinePolicy."
126
  set policy (aStr) {
127
    this._policy = CSPRep.fromString(aStr);
128
  },
129
  */
130
131
  /**
132
   * Given an nsIHttpChannel, fill out the appropriate data.
133
   */
134
  scanRequestData:
135
  function(aChannel) {
136
    // grab the request line
137
    var internalChannel = aChannel.QueryInterface(Ci.nsIHttpChannelInternal);
138
    var reqMaj = {};
139
    var reqMin = {};
140
    var reqVersion = internalChannel.getRequestVersion(reqMaj, reqMin);
141
    this._request = aChannel.requestMethod + " " 
142
                  + aChannel.URI 
143
                  + " HTTP/" + reqMaj.value + "." + reqMin.value;
144
145
    // grab the request headers
146
    var self = this;
147
    aChannel.visitRequestHeaders({
148
      visitHeader: function(aHeader, aValue) {
149
        self._requestHeaders.push(aHeader + ": " + aValue);
150
      }});
151
  },
152
153
/* ........ Methods .............. */
154
155
  /**
156
   * Given a new policy, intersects the currently enforced policy with the new
157
   * one and stores the result.  The effect is a "tightening" or refinement of
158
   * an old policy.  This is called any time a new policy is encountered and
159
   * the effective policy has to be refined.
160
   */
161
  refinePolicy:
162
  function csp_refinePolicy(aPolicy, selfURI) {
163
    CSPdebug("REFINE POLICY: " + aPolicy);
164
    CSPdebug("         SELF: " + selfURI.asciiSpec);
165
166
    // stay uninitialized until policy merging is done
167
    this._isInitialized = false;
168
169
    // If there is a policy-uri, fetch the policy, then re-call this function.
170
    // (1) parse and create a CSPRep object
171
    var newpolicy = CSPRep.fromString(aPolicy,
172
                                      selfURI.scheme + "://" + selfURI.hostPort);
173
174
    // (2) Intersect the currently installed CSPRep object with the new one
175
    var intersect = this._policy.intersectWith(newpolicy);
176
    //TODO: make sure intersect worked
177
 
178
    // (3) Save the result
179
    this._policy = intersect;
180
    this._isInitialized = true;
181
  },
182
183
  /**
184
   * Generates and sends a violation report to the specified report URIs.
185
   */
186
  sendReports:
187
  function(blockedUri, violatedDirective) {
188
    var uris = this._policy.getReportURIs();
189
    if(uris.length > 0) {
190
      // Generate report to send composed of:
191
      // <csp-report>
192
      //   <request>GET /index.html HTTP/1.1</request>
193
      //   <request-headers>Host: example.com
194
      //            User-Agent: ...
195
      //            ...
196
      //   </request-headers>
197
      //   <blocked-uri>...</blocked-uri>
198
      //   <violated-directive>...</violated-directive>
199
      // </csp-report>
200
      //   
201
      var strHeaders = "";
202
      for(let i in this._requestHeaders) {
203
        strHeaders += this._requestHeaders[i] + "\n";
204
      }
205
206
      var report = "<csp-report>\n" +
207
        " <request>" + this._request + "</request>\n" +
208
        "   <request-headers><![CDATA[\n" +
209
        strHeaders +
210
        "   ]]></request-headers>\n" +
211
        "   <blocked-uri>" + blockedUri + "</blocked-uri>\n" +
212
        "   <violated-directive>" + violatedDirective + "</violated-directive>\n" +
213
        "</csp-report>\n";
214
215
      // For each URI in the report list, send out a report.
216
      for(let i in uris) {
217
        var failure = function(aEvt) {  
218
          if(req.readyState == 4 && req.status != 200) {
219
            CSPError("Failed to send report to " + reportURI);
220
          }  
221
        };  
222
        var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]  
223
                    .createInstance(Ci.nsIXMLHttpRequest);  
224
225
        req.open("POST", uris[i], true);
226
        req.upload.addEventListener("error", failure, false);  
227
        req.upload.addEventListener("abort", failure, false);  
228
        //req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
229
 
230
        // make request anonymous
231
        // This prevents sending cookies with the request, 
232
        // in case the policy URI is injected, it can't be
233
        // abused for CSRF.
234
        req.channel.loadFlags |= Ci.nsIChannel.LOAD_ANONYMOUS;
235
236
        req.send(report);
237
      }
238
    }
239
  },
240
241
  /**
242
   * Exposed Method to analyze docShell for approved frame ancestry.
243
   * Also sends violation reports if necessary.
244
   * @param docShell
245
   *    the docShell for this policy's resource.
246
   * @return
247
   *    true if the frame ancestry is allowed by this policy.
248
   */
249
  permitsAncestry:
250
  function(docShell) {
251
    if(!docShell) { return false; }
252
    CSPdebug(" in permitsAncestry(), docShell = " + docShell);
253
254
    // walk up this docShell tree until we hit chrome
255
    var dst = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
256
                      .getInterface(Ci.nsIDocShellTreeItem);
257
258
    // collect ancestors and make sure they're allowed.
259
    var ancestors = [];
260
    while(dst.parent) {
261
      dst = dst.parent;
262
      let it = dst.QueryInterface(Ci.nsIInterfaceRequestor)
263
                  .getInterface(Ci.nsIWebNavigation);
264
      if(it.currentURI) {
265
        if(it.currentURI.scheme == "chrome") {
266
          break;
267
        }
268
        let ancestor = it.currentURI.scheme + "://" + it.currentURI.hostPort;
269
        CSPdebug(" found frame ancestor " + ancestor);
270
        ancestors.push(ancestor);
271
      }
272
    } 
273
274
    // scan the discovered ancestors
275
    let cspContext = CSPRep.SRC_DIRECTIVES.FRAME_ANCESTORS;
276
    for(let i in ancestors) {
277
      if(!this._policy.permits(ancestors[i], cspContext)) {
278
        // report the frame-ancestor violation
279
        this.sendReports("self", cspContext +" "+ this._policy._directives[cspContext]);
280
        return false;
281
      }
282
    }
283
    return true;
284
  },
285
286
  /**
287
   * Delegate method called by the service when sub-elements of the protected
288
   * document are being loaded.  Given a bit of information about the request,
289
   * decides whether or not the policy is satisfied.
290
   */
291
  shouldLoad:
292
  function csp_shouldLoad(aContentType, 
293
                          aContentLocation, 
294
                          aRequestOrigin, 
295
                          aContext, 
296
                          aMimeTypeGuess, 
297
                          aExtra) {
298
299
    //don't filter chrome stuff
300
    if(aContentLocation.scheme == 'chrome') {
301
      return Ci.nsIContentPolicy.ACCEPT;
302
    }
303
304
    //interpret the context, and then pass off to the decision structure
305
    CSPdebug("shouldLoad location = " + aContentLocation.asciiSpec);
306
    CSPdebug("shouldLoad content type = " + aContentType);
307
    var cspContext = ContentSecurityPolicy._MAPPINGS[aContentType];
308
    //CSPdebug("shouldLoad CSP directive =" + cspContext);
309
310
    // if the mapping is null, there's no policy, let it through.
311
    if(!cspContext) {
312
      return Ci.nsIContentPolicy.ACCEPT;
313
    }
314
315
    // otherwise, honor the translation
316
    //var source = aContentLocation.scheme + "://" + aContentLocation.hostPort; 
317
    var res = this._policy.permits(aContentLocation, cspContext)
318
              ? Ci.nsIContentPolicy.ACCEPT 
319
              : Ci.nsIContentPolicy.REJECT_SERVER;
320
321
    // frame-ancestors is taken care of early on (as this document is loaded)
322
323
    // If the result is *NOT* ACCEPT, then send report
324
    if(res != Ci.nsIContentPolicy.ACCEPT) { 
325
      CSPdebug("blocking request for " + aContentLocation.asciiSpec);
326
      this.sendReports(aContentLocation,
327
                       cspContext + " " + this._policy._directives[cspContext]);
328
    }
329
330
    return res;
331
  },
332
  
333
  shouldProcess:
334
  function csp_shouldProcess(aContentType,
335
                             aContentLocation,
336
                             aRequestOrigin,
337
                             aContext,
338
                             aMimeType,
339
                             aExtra) {
340
    // frame-ancestors check is done outside the ContentPolicy
341
    var res = Ci.nsIContentPolicy.ACCEPT;
342
    CSPdebug("shouldProcess aContext=" + aContext);
343
    return res;
344
  },
345
346
};
347
348
349
350
function NSGetModule(aComMgr, aFileSpec)
351
  XPCOMUtils.generateModule([ContentSecurityPolicy]);
(-)a/caps/tests/Makefile.in (+4 lines)
Line     Link Here 
 Lines 40-48   DEPTH = ../.. Link Here 
40
topsrcdir	= @top_srcdir@
40
topsrcdir	= @top_srcdir@
41
srcdir		= @srcdir@
41
srcdir		= @srcdir@
42
VPATH		= @srcdir@
42
VPATH		= @srcdir@
43
43
44
include $(DEPTH)/config/autoconf.mk
44
include $(DEPTH)/config/autoconf.mk
45
45
46
DIRS = mochitest
46
DIRS = mochitest
47
47
48
MODULE = test_caps
49
50
XPCSHELL_TESTS = unit
51
48
include $(topsrcdir)/config/rules.mk
52
include $(topsrcdir)/config/rules.mk
(-)f46e6aee1335 (+472 lines)
Added Link Here 
Added Link Here 
1
/* ***** BEGIN LICENSE BLOCK *****
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3
 *
4
 * The contents of this file are subject to the Mozilla Public License Version
5
 * 1.1 (the "License"); you may not use this file except in compliance with
6
 * the License. You may obtain a copy of the License at
7
 * http://www.mozilla.org/MPL/
8
 *
9
 * Software distributed under the License is distributed on an "AS IS" basis,
10
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
 * for the specific language governing rights and limitations under the
12
 * License.
13
 *
14
 * The Original Code is the Content Security Policy Data Structures testing code.
15
 *
16
 * The Initial Developer of the Original Code is
17
 * Sid Stamm <sid@mozilla.com>
18
 *
19
 * Contributor(s):
20
 *
21
 * Alternatively, the contents of this file may be used under the terms of
22
 * either the GNU General Public License Version 2 or later (the "GPL"), or
23
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
24
 * in which case the provisions of the GPL or the LGPL are applicable instead
25
 * of those above. If you wish to allow use of your version of this file only
26
 * under the terms of either the GPL or the LGPL, and not to allow others to
27
 * use your version of this file under the terms of the MPL, indicate your
28
 * decision by deleting the provisions above and replace them with the notice
29
 * and other provisions required by the GPL or the LGPL. If you do not delete
30
 * the provisions above, a recipient may use your version of this file under
31
 * the terms of any one of the MPL, the GPL or the LGPL.
32
 *
33
 * ***** END LICENSE BLOCK ***** */
34
35
//load('CSPUtils.jsm');
36
Components.utils.import('resource://gre/modules/CSPUtils.jsm');
37
38
// load the HTTP server
39
do_load_httpd_js();
40
41
var httpServer = new nsHttpServer();
42
43
const POLICY_FROM_URI = "allow self; img-src *";
44
const POLICY_PORT = 9000;
45
const POLICY_URI = "http://localhost:" + POLICY_PORT + "/policy";
46
47
// helper to assert that an object or array must have a given key
48
function do_check_has_key(foo, key, stack) {
49
  if (!stack) 
50
    stack = Components.stack.caller;
51
52
  var keys = [];
53
  for(let k in keys) { keys.push(k); }
54
  var text = key + " in [" + keys.join(",") + "]";
55
56
  for(var x in foo) {
57
    if(x == key) {
58
      //succeed
59
      ++_passedChecks;
60
      dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
61
           stack.lineNumber + "] " + text + "\n");
62
      return;
63
    }
64
  }
65
  do_throw(text, stack);
66
}
67
68
// helper to use .equals on stuff
69
function do_check_equivalent(foo, bar, stack) {
70
  if (!stack) 
71
    stack = Components.stack.caller;
72
73
  var text = foo + ".equals(" + bar + ")";
74
75
  if(foo.equals && foo.equals(bar)) {
76
    ++_passedChecks;
77
      dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
78
           stack.lineNumber + "] " + text + "\n");
79
      return;
80
  }
81
  do_throw(text, stack);
82
}
83
84
var tests = [];
85
function test(fcn) {
86
  tests.push(fcn);
87
}
88
89
test(
90
  function test_CSPHost_fromstring() {
91
    var h;
92
93
    h = CSPHost.fromString("*");
94
    do_check_neq(null, h); // "* lone wildcard should work"
95
96
    h = CSPHost.fromString("foo.bar");
97
    do_check_neq(null, h); // "standard tuple failed"
98
99
    h = CSPHost.fromString("*.bar");
100
    do_check_neq(null, h); // "wildcard failed"
101
102
    h = CSPHost.fromString("com");
103
    do_check_eq(null, h); // "lone symbol should fail"
104
105
    h = CSPHost.fromString("f00b4r.com");
106
    do_check_neq(null, h); // "Numbers in hosts should work"
107
108
    h = CSPHost.fromString("foo-bar.com");
109
    do_check_neq(null, h); // "dashes in hosts should work"
110
111
    // Not enforced in CSPHost
112
    //h = CSPHost.fromString("foo!bar.com");
113
    //ASSERT_NULL(h, "special chars in hosts should fail");
114
  });
115
116
test(
117
  function test_CSPHost_clone() {
118
    h = CSPHost.fromString("*.a.b.c");
119
    h2 = h.clone();
120
    for(var i in h._segments) {
121
      // "cloned segments should match"
122
      do_check_eq(h._segments[i], h2._segments[i]);
123
    }
124
  });
125
126
test(
127
  function test_CSPHost_permits() {
128
    var h = CSPHost.fromString("*.b.c");
129
    var h2 = CSPHost.fromString("a.b.c");
130
    do_check_true( h.permits(h2));       //"CSPHost *.b.c should allow CSPHost a.b.c"
131
    do_check_true( h.permits("a.b.c"));  //"CSPHost *.b.c should allow string a.b.c"
132
    do_check_true(!h.permits("b.c"));    //"CSPHost *.b.c should not allow string b.c"
133
    do_check_true(!h.permits("a.a.c"));  //"CSPHost *.b.c should not allow string a.a.c"
134
    do_check_true(!h2.permits(h));       //"CSPHost a.b.c should not allow CSPHost *.b.c"
135
    do_check_true(!h2.permits("b.c"));   //"CSPHost a.b.c should not allow string b.c"
136
    do_check_true( h2.permits("a.b.c")); //"CSPHost a.b.c should allow string a.b.c"
137
  });
138
139
test(
140
    function test_CSPHost_intersectWith() {
141
      var h = CSPHost.fromString("*.b.c");
142
      //"*.a.b.c ^ *.b.c should be *.a.b.c"
143
      do_check_eq("*.a.b.c", h.intersectWith(CSPHost.fromString("*.a.b.c")).toString());
144
145
      //"*.b.c ^ *.d.e should not work (null)"
146
      do_check_eq(null, h.intersectWith(CSPHost.fromString("*.d.e")));
147
    });
148
149
///////////////////// Test the Source object //////////////////////
150
151
test(
152
    function test_CSPSource_fromString() {
153
      //"basic source should not be null.");
154
      /*
155
      do_check_neq(null, CSPSource.fromString("a.com"));
156
157
      //"ldh characters should all work for host.");
158
      do_check_neq(null, CSPSource.fromString("a2-c.com"));
159
160
      //"wildcard should work in first token for host.");
161
      do_check_neq(null, CSPSource.fromString("*.a.com"));
162
163
      //print(" --- Ignore the following two errors if they print ---");
164
      //"wildcard should not work in non-first token for host.");
165
      do_check_eq(null, CSPSource.fromString("x.*.a.com"));
166
167
      //"funny characters (#) should not work for host, _HOST_RE is probably broken.");
168
      do_check_eq(null, CSPSource.fromString("a#2-c.com"));
169
      //print(" --- Stop ignoring errors that print ---\n");
170
      */
171
172
      //"failed to parse host with port.");
173
      do_check_neq(null, CSPSource.fromString("a.com:23"));
174
      //"failed to parse host with scheme.");
175
      do_check_neq(null, CSPSource.fromString("https://a.com"));
176
      //"failed to parse host with scheme and port.");
177
      do_check_neq(null, CSPSource.fromString("https://a.com:200"));
178
    });
179
180
test(
181
    function test_CSPSource_fromString_withSelf() {
182
      var src;
183
      src = CSPSource.fromString("a.com", "https://self.com");
184
      //"src should inherit port *
185
      do_check_true(src.permits("https://a.com:443"));
186
      //"src should inherit and require https scheme
187
      do_check_false(src.permits("http://a.com"));
188
      //"src should inherit scheme 'https'"
189
      do_check_true(src.permits("https://a.com"));
190
      
191
      src = CSPSource.fromString("self", "https://self.com");
192
      //"src should inherit port *
193
      do_check_true(src.permits("https://self.com:443"));
194
      //"src should inherit and require https scheme
195
      do_check_false(src.permits("http://self.com"));
196
      //"src should inherit scheme 'https'"
197
      do_check_true(src.permits("https://self.com"));
198
      //"src should reject other hosts"
199
      do_check_false(src.permits("https://a.com"));
200
    });
201
202
///////////////////// Test the source list //////////////////////
203
204
test(
205
    function test_CSPSourceList_fromString() {
206
      var sd = CSPSourceList.fromString("none");
207
      //"'none' -- should parse"
208
      do_check_neq(null,sd);
209
      // "'none' should be a zero-length list"
210
      do_check_eq(0, sd._sources.length);
211
212
      sd = CSPSourceList.fromString("*");
213
      //"'*' should be a one-length list"
214
      do_check_eq(1, sd._sources.length);
215
216
      //print(" --- Ignore the following three errors if they print ---");
217
      //"funny char in host"
218
      do_check_eq(null,CSPSourceList.fromString("f!oo.bar"));
219
      //"funny char in scheme"
220
      do_check_eq(null,CSPSourceList.fromString("ht1ps://f-oo.bar"));
221
      //"funny char in port"
222
      do_check_eq(null,CSPSourceList.fromString("https://f-oo.bar:3f"));
223
      //print(" --- Stop ignoring errors that print ---\n");
224
    });
225
226
test(
227
    function test_CSPSourceList_fromString_twohost() {
228
      var str = "foo.bar:21 https://ras.bar";
229
      var sd = CSPSourceList.fromString(str);
230
      //"two-host list should parse"
231
      do_check_neq(null,sd);
232
      //"two-host list should parse to two hosts"
233
      do_check_eq(2, sd._sources.length);
234
      //"two-host list should contain original data"
235
      do_check_eq(str, sd.toString());
236
    });
237
238
test(
239
    function test_CSPSourceList_permits() {
240
      var nullSourceList = CSPSourceList.fromString("none");
241
      var simpleSourceList = CSPSourceList.fromString("a.com");
242
      var doubleSourceList = CSPSourceList.fromString("https://foo.com http://bar.com:88");
243
      var allSourceList = CSPSourceList.fromString("*");
244
245
      //'none' should permit none."
246
      do_check_true( !nullSourceList.permits("a.com"));
247
      //a.com should permit a.com"
248
      do_check_true( simpleSourceList.permits("a.com"));
249
      //wrong host"
250
      do_check_true( !simpleSourceList.permits("b.com"));
251
      //double list permits http://bar.com:88"
252
      do_check_true( doubleSourceList.permits("http://bar.com:88"));
253
      //double list permits https://bar.com:88"
254
      do_check_true( !doubleSourceList.permits("https://bar.com:88"));
255
      //double list does not permit http://bar.com:443"
256
      do_check_true( !doubleSourceList.permits("http://bar.com:443"));
257
      //"double list permits https://foo.com:88"
258
      do_check_true( doubleSourceList.permits("https://foo.com:88"));
259
      //"double list does not permit foo.com"
260
      do_check_true( !doubleSourceList.permits("foo.com"));
261
262
      //"* does not permit specific host"
263
      do_check_true( allSourceList.permits("http://x.com:23"));
264
      //"* does not permit a long host with no port"
265
      do_check_true( allSourceList.permits("http://a.b.c.d.e.f.x.com"));
266
267
    });
268
269
test(
270
    function test_CSPSourceList_intersect() {
271
      var nullSourceList = CSPSourceList.fromString("none");
272
      var simpleSourceList = CSPSourceList.fromString("a.com");
273
      var doubleSourceList = CSPSourceList.fromString("https://foo.com http://bar.com:88");
274
      var singleFooSourceList = CSPSourceList.fromString("https://foo.com");
275
      var allSourceList = CSPSourceList.fromString("*");
276
277
      //"Intersection of one source with 'none' source list should be none.");
278
      do_check_true(nullSourceList.intersectWith(simpleSourceList).isNone());
279
      //"Intersection of two sources with 'none' source list should be none.");
280
      do_check_true(nullSourceList.intersectWith(doubleSourceList).isNone());
281
      //"Intersection of '*' with 'none' source list should be none.");
282
      do_check_true(nullSourceList.intersectWith(allSourceList).isNone());
283
284
      //"Intersection of one source with '*' source list should be one source.");
285
      do_check_equivalent(allSourceList.intersectWith(simpleSourceList),
286
                          simpleSourceList);
287
      //"Intersection of two sources with '*' source list should be two sources.");
288
      do_check_equivalent(allSourceList.intersectWith(doubleSourceList),
289
                          doubleSourceList);
290
291
      //"Non-overlapping source lists should intersect to 'none'");
292
      do_check_true(simpleSourceList.intersectWith(doubleSourceList).isNone());
293
294
      //"subset and superset should intersect to subset.");
295
      do_check_equivalent(singleFooSourceList,
296
                          doubleSourceList.intersectWith(singleFooSourceList));
297
298
      //TODO: write more tests?
299
300
    });
301
302
///////////////////// Test the Whole CSP rep object //////////////////////
303
304
test(
305
    function test_CSPRep_fromString() {
306
307
      // check default init
308
      //ASSERT(!(new CSPRep())._isInitialized, "Uninitialized rep thinks it is.")
309
310
      var cspr;
311
      var cspr_allowval;
312
313
      // check default policy "allow *"
314
      cspr = CSPRep.fromString("allow *");
315
      //"ALLOW directive is missing when specified in fromString"
316
      do_check_has_key(cspr._directives, CSPRep.SRC_DIRECTIVES.ALLOW);
317
318
      // ... and check that the other directives were auto-filled with the
319
      // ALLOW one.
320
      var SD = CSPRep.SRC_DIRECTIVES;
321
      cspr_allowval = cspr._directives[SD.ALLOW];
322
      for(var d in CSPRep.SRC_DIRECTIVES) {
323
        //"Missing key " + d
324
        do_check_has_key(cspr._directives, SD[d]);
325
        //"Implicit directive " + d + " has non-allow value."
326
        do_check_eq(cspr._directives[SD[d]].toString(), cspr_allowval.toString());
327
      }
328
    });
329
330
331
test(
332
    function test_CSPRep_fromString_oneDir() {
333
334
      var cspr;
335
      var SD = CSPRep.SRC_DIRECTIVES;
336
      var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.IMG_SRC,
337
                      SD.FRAME_ANCESTORS, SD.FRAME_SRC];
338
339
      // check one-directive policies
340
      cspr = CSPRep.fromString("allow bar.com; script-src https://foo.com");
341
342
      for(var x in DEFAULTS) {
343
        //DEFAULTS[x] + " does not use default rule."
344
        do_check_true(cspr.permits("http://bar.com:22", DEFAULTS[x]));
345
        //DEFAULTS[x] + " does not use default rule."
346
        do_check_false(cspr.permits("https://foo.com:400", DEFAULTS[x]));
347
      }
348
      //"script-src false positive in policy.
349
      do_check_false(cspr.permits("http://bar.com:22", SD.SCRIPT_SRC));
350
      //"script-src false negative in policy.
351
      do_check_true(cspr.permits("https://foo.com:400", SD.SCRIPT_SRC));
352
    });
353
354
test(
355
    function test_CSPRep_fromString_twodir() {
356
      var cspr;
357
      var SD = CSPRep.SRC_DIRECTIVES;
358
      var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.FRAME_ANCESTORS, SD.FRAME_SRC];
359
360
      // check two-directive policies
361
      cspr = CSPRep.fromString("allow allow.com; "
362
                             + "script-src https://foo.com; "
363
                             + "img-src bar.com");
364
      for(var x in DEFAULTS) {
365
        do_check_true(cspr.permits("http://allow.com:22", DEFAULTS[x]));
366
        //DEFAULTS[x] + " does not use default rule.
367
        do_check_false(cspr.permits("https://foo.com:400", DEFAULTS[x]));
368
        //DEFAULTS[x] + " does not use default rule.
369
        do_check_false(cspr.permits("http://bar.com:400", DEFAULTS[x]));
370
        //DEFAULTS[x] + " does not use default rule.
371
      }
372
      //"img-src does not use default rule.
373
      do_check_false(cspr.permits("http://allow.com:22", SD.IMG_SRC));
374
      //"img-src does not use default rule.
375
      do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
376
      //"img-src does not use default rule.
377
      do_check_true(cspr.permits("http://bar.com:400", SD.IMG_SRC));
378
379
      //"script-src does not use default rule.
380
      do_check_false(cspr.permits("http://allow.com:22", SD.SCRIPT_SRC));
381
      //"script-src does not use default rule.
382
      do_check_true(cspr.permits("https://foo.com:400", SD.SCRIPT_SRC));
383
      //"script-src does not use default rule.
384
      do_check_false(cspr.permits("http://bar.com:400", SD.SCRIPT_SRC));
385
    });
386
387
test(function test_CSPRep_fromString_withself() {
388
       var cspr;
389
       var SD = CSPRep.SRC_DIRECTIVES;
390
       var self = "https://self.com:34";
391
392
       // check one-directive policies
393
       cspr = CSPRep.fromString("allow self; script-src self https://*:*",
394
                                self);
395
      //"img-src does not enforce default rule, 'self'.
396
      do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
397
      //"img-src does not allow self
398
      do_check_true(cspr.permits(self, SD.IMG_SRC));
399
      //"script-src is too relaxed
400
      do_check_false(cspr.permits("http://evil.com", SD.SCRIPT_SRC));
401
      //"script-src should allow self
402
      do_check_true(cspr.permits(self, SD.SCRIPT_SRC));
403
      //"script-src is too strict on host/port
404
      do_check_true(cspr.permits("https://evil.com:100", SD.SCRIPT_SRC));
405
     });
406
407
///////////////////// TEST POLICY_URI //////////////////////
408
test(function test_CSPRep_fromPolicyURI() {
409
        var cspr;
410
        var SD = CSPRep.SRC_DIRECTIVES;
411
        var self = "http://localhost:" + POLICY_PORT;
412
413
        cspr = CSPRep.fromString("policy-uri " + POLICY_URI, self);
414
        cspr_static = CSPRep.fromString(POLICY_FROM_URI, self);
415
416
        //"policy-uri failed to load"
417
        do_check_neq(null,cspr);
418
419
        // other directives inherit self
420
        for(var i in SD) {
421
          //SD[i] + " parsed wrong from policy uri"
422
          do_check_equivalent(cspr._directives[SD[i]],
423
                              cspr_static._directives[SD[i]]);
424
        }
425
    });
426
/*
427
428
test(function test_CSPRep_fromPolicyURI_failswhenmixed() {
429
        var cspr;
430
        var self = "http://localhost:" + POLICY_PORT;
431
        var closed_policy = CSPRep.fromString("allow none");
432
        var my_uri_policy = "policy-uri " + POLICY_URI;
433
434
        //print(" --- Ignore the following two errors if they print ---");
435
        cspr = CSPRep.fromString("allow *; " + my_uri_policy, self);
436
437
        //"Parsing should fail when 'policy-uri' is mixed with allow directive"
438
        do_check_equivalent(cspr, closed_policy);
439
        cspr = CSPRep.fromString("img-src self; " + my_uri_policy, self);
440
441
        //"Parsing should fail when 'policy-uri' is mixed with other directives"
442
        do_check_equivalent(cspr, closed_policy);
443
        //print(" --- Stop ignoring errors that print ---\n");
444
445
    });
446
*/
447
448
// TODO: test reporting
449
// TODO: test refinements (?)
450
// TODO: test 'eval' and 'inline' keywords
451
452
function run_test() {
453
  function policyresponder(request,response) {
454
    response.setStatusLine(request.httpVersion, 200, "OK");
455
    response.setHeader("Content-Type", "text/csp", false);
456
    response.bodyOutputStream.write(POLICY_FROM_URI, POLICY_FROM_URI.length);
457
  }
458
  //server.registerDirectory("/", nsILocalFileForBasePath);
459
  httpServer.registerPathHandler("/policy", policyresponder);
460
  httpServer.start(POLICY_PORT);
461
462
  for(let i in tests) {
463
    tests[i]();
464
  }
465
466
  //teardown
467
  httpServer.stop(function() { });
468
  do_test_finished();
469
}
470
471
472
(-)a/content/base/public/nsIDocument.h (+12 lines)
Line     Link Here 
 Lines 52-67    Link Here 
52
#include "nsCompatibility.h"
52
#include "nsCompatibility.h"
53
#include "nsTObserverArray.h"
53
#include "nsTObserverArray.h"
54
#include "nsTHashtable.h"
54
#include "nsTHashtable.h"
55
#include "nsHashKeys.h"
55
#include "nsHashKeys.h"
56
#include "nsNodeInfoManager.h"
56
#include "nsNodeInfoManager.h"
57
#include "nsIStreamListener.h"
57
#include "nsIStreamListener.h"
58
#include "nsIObserver.h"
58
#include "nsIObserver.h"
59
#include "nsAutoPtr.h"
59
#include "nsAutoPtr.h"
60
#include "IContentSecurityPolicy.h"
60
#ifdef MOZ_SMIL
61
#ifdef MOZ_SMIL
61
class nsSMILAnimationController;
62
class nsSMILAnimationController;
62
#endif // MOZ_SMIL
63
#endif // MOZ_SMIL
63
64
64
class nsIContent;
65
class nsIContent;
65
class nsPresContext;
66
class nsPresContext;
66
class nsIPresShell;
67
class nsIPresShell;
67
class nsIDocShell;
68
class nsIDocShell;
 Lines 1057-1072   public: Link Here 
1057
                    "have a presentation or a docshell or a window");
1058
                    "have a presentation or a docshell or a window");
1058
    NS_PRECONDITION(aDisplayDocument != this, "Should be different document");
1059
    NS_PRECONDITION(aDisplayDocument != this, "Should be different document");
1059
    NS_PRECONDITION(!aDisplayDocument->GetDisplayDocument(),
1060
    NS_PRECONDITION(!aDisplayDocument->GetDisplayDocument(),
1060
                    "Display documents should not nest");
1061
                    "Display documents should not nest");
1061
    mDisplayDocument = aDisplayDocument;
1062
    mDisplayDocument = aDisplayDocument;
1062
  }
1063
  }
1063
1064
1064
  /**
1065
  /**
1066
   * Return the Content Security Policy object for the document
1067
   */
1068
  IContentSecurityPolicy* GetContentSecurityPolicy() const
1069
  {
1070
    return mCSP;
1071
  }
1072
1073
  /**
1065
   * A class that represents an external resource load that has begun but
1074
   * A class that represents an external resource load that has begun but
1066
   * doesn't have a document yet.  Observers can be registered on this object,
1075
   * doesn't have a document yet.  Observers can be registered on this object,
1067
   * and will be notified after the document is created.  Observers registered
1076
   * and will be notified after the document is created.  Observers registered
1068
   * after the document has been created will NOT be notified.  When observers
1077
   * after the document has been created will NOT be notified.  When observers
1069
   * are notified, the subject will be the newly-created document, the topic
1078
   * are notified, the subject will be the newly-created document, the topic
1070
   * will be "external-resource-document-created", and the data will be null.
1079
   * will be "external-resource-document-created", and the data will be null.
1071
   * If document creation fails for some reason, observers will still be
1080
   * If document creation fails for some reason, observers will still be
1072
   * notified, with a null document pointer.
1081
   * notified, with a null document pointer.
 Lines 1258-1273   protected: Link Here 
1258
  PRUint32            mSubtreeModifiedDepth;
1267
  PRUint32            mSubtreeModifiedDepth;
1259
1268
1260
  // If we're an external resource document, this will be non-null and will
1269
  // If we're an external resource document, this will be non-null and will
1261
  // point to our "display document": the one that all resource lookups should
1270
  // point to our "display document": the one that all resource lookups should
1262
  // go to.
1271
  // go to.
1263
  nsCOMPtr<nsIDocument> mDisplayDocument;
1272
  nsCOMPtr<nsIDocument> mDisplayDocument;
1264
1273
1265
  PRUint32 mEventsSuppressed;
1274
  PRUint32 mEventsSuppressed;
1275
1276
  // CSP policy object/data
1277
  nsCOMPtr<IContentSecurityPolicy> mCSP;
1266
};
1278
};
1267
1279
1268
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
1280
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
1269
1281
1270
/**
1282
/**
1271
 * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
1283
 * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
1272
 * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
1284
 * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
1273
 * object is deleted.
1285
 * object is deleted.
(-)a/content/base/src/Makefile.in (+1 lines)
Line     Link Here 
 Lines 117-132   CPPSRCS = \ Link Here 
117
		nsContentAreaDragDrop.cpp \
117
		nsContentAreaDragDrop.cpp \
118
		nsContentIterator.cpp \
118
		nsContentIterator.cpp \
119
		nsContentList.cpp \
119
		nsContentList.cpp \
120
		nsContentPolicy.cpp \
120
		nsContentPolicy.cpp \
121
		nsContentSink.cpp \
121
		nsContentSink.cpp \
122
		nsContentUtils.cpp \
122
		nsContentUtils.cpp \
123
		nsCopySupport.cpp \
123
		nsCopySupport.cpp \
124
		nsCrossSiteListenerProxy.cpp \
124
		nsCrossSiteListenerProxy.cpp \
125
		nsCSPService.cpp \
125
		nsDataDocumentContentPolicy.cpp \
126
		nsDataDocumentContentPolicy.cpp \
126
		nsDOMAttribute.cpp \
127
		nsDOMAttribute.cpp \
127
		nsDOMAttributeMap.cpp \
128
		nsDOMAttributeMap.cpp \
128
		nsDOMDocumentType.cpp \
129
		nsDOMDocumentType.cpp \
129
		nsDOMFile.cpp \
130
		nsDOMFile.cpp \
130
		nsDOMLists.cpp \
131
		nsDOMLists.cpp \
131
		nsDOMParser.cpp \
132
		nsDOMParser.cpp \
132
		nsDOMSerializer.cpp \
133
		nsDOMSerializer.cpp \
(-)f46e6aee1335 (+177 lines)
Added Link Here 
Added Link Here 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
 *
5
 * The contents of this file are subject to the Mozilla Public License Version
6
 * 1.1 (the "License"); you may not use this file except in compliance with
7
 * the License. You may obtain a copy of the License at
8
 * http://www.mozilla.org/MPL/
9
 *
10
 * Software distributed under the License is distributed on an "AS IS" basis,
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
 * for the specific language governing rights and limitations under the
13
 * License.
14
 *
15
 * The Original Code is mozilla.org code.
16
 *
17
 * The Initial Developer of the Original Code is
18
 * Mozilla Corporation.
19
 * Portions created by the Initial Developer are Copyright (C) 2009
20
 * the Initial Developer. All Rights Reserved.
21
 *
22
 * Contributor(s):
23
 *   Brandon Sterne <bsterne@mozilla.com>
24
 *
25
 * Alternatively, the contents of this file may be used under the terms of
26
 * either of the GNU General Public License Version 2 or later (the "GPL"),
27
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
 * in which case the provisions of the GPL or the LGPL are applicable instead
29
 * of those above. If you wish to allow use of your version of this file only
30
 * under the terms of either the GPL or the LGPL, and not to allow others to
31
 * use your version of this file under the terms of the MPL, indicate your
32
 * decision by deleting the provisions above and replace them with the notice
33
 * and other provisions required by the GPL or the LGPL. If you do not delete
34
 * the provisions above, a recipient may use your version of this file under
35
 * the terms of any one of the MPL, the GPL or the LGPL.
36
 *
37
 * ***** END LICENSE BLOCK ***** */
38
39
#include "nsIURI.h"
40
#include "nsString.h"
41
#include "nsCSPService.h"
42
#include "nsIDocument.h"
43
#include "nsIContent.h"
44
#include "IContentSecurityPolicy.h"
45
46
CSPService::CSPService()
47
{
48
}
49
50
CSPService::~CSPService()
51
{
52
}
53
54
NS_IMPL_ISUPPORTS1(CSPService, nsIContentPolicy)
55
56
/* nsIContentPolicy implementation */
57
NS_IMETHODIMP
58
CSPService::ShouldLoad(PRUint32 aContentType,
59
                       nsIURI *aContentLocation,
60
                       nsIURI *aRequestOrigin,
61
                       nsISupports *aRequestContext,
62
                       const nsACString &aMimeTypeGuess,
63
                       nsISupports *aExtra,
64
                       PRInt16 *aDecision)
65
{
66
  if (!aContentLocation)
67
    return NS_ERROR_FAILURE;
68
69
#ifdef DEBUG
70
  {
71
    nsCAutoString location("None");
72
    aContentLocation->GetSpec(location);
73
    printf(" *** CSPService::ShouldLoad called for %s\n",
74
           location.get());
75
  }
76
#endif
77
78
  // find the nsDocument that initiated this request and see if it has a
79
  // CSP policy object
80
  nsCOMPtr<nsIDocument> doc;
81
  nsCOMPtr<nsIContent> node(do_QueryInterface(aRequestContext));
82
  if (node) {
83
    doc = node->GetOwnerDoc();
84
  }
85
  if (!doc) {
86
    doc = do_QueryInterface(aRequestContext);
87
  }
88
  
89
  // default decision, CSP can revise it if there's a policy to enforce
90
  *aDecision = nsIContentPolicy::ACCEPT;
91
  if (doc) {
92
    IContentSecurityPolicy* csp = doc->GetContentSecurityPolicy();
93
    if (csp) {
94
#ifdef DEBUG
95
      nsAutoString policy;
96
      csp->GetPolicy(policy);
97
      printf(" *** CSPService - document has policy: %s\n",
98
              ToNewCString(policy));
99
#endif
100
      // obtain the enforcement decision
101
      csp->ShouldLoad(aContentType,
102
                      aContentLocation,
103
                      aRequestOrigin,
104
                      aRequestContext,
105
                      aMimeTypeGuess,
106
                      aExtra,
107
                      aDecision);
108
    }
109
  }
110
#ifdef DEBUG
111
  else {
112
    nsCAutoString uriSpec("None");
113
    aContentLocation->GetSpec(uriSpec);
114
    printf(" *** CSPService - COULD NOT get nsIDocument for location: %s\n",
115
            uriSpec.get());
116
  }
117
#endif
118
	
119
  return NS_OK;
120
}
121
122
NS_IMETHODIMP
123
CSPService::ShouldProcess(PRUint32         aContentType,
124
                          nsIURI           *aContentLocation,
125
                          nsIURI           *aRequestOrigin,
126
                          nsISupports      *aRequestContext,
127
                          const nsACString &aMimeTypeGuess,
128
                          nsISupports      *aExtra,
129
                          PRInt16          *aDecision)
130
{
131
  if (!aContentLocation)
132
    return NS_ERROR_FAILURE;
133
134
  // This check is only useful for deciding about frame-ancestors
135
  
136
  // default decision is to accept the item
137
  *aDecision = nsIContentPolicy::ACCEPT;
138
139
  // find the nsDocument that initiated this request and see if it has a
140
  // CSP policy object
141
  nsCOMPtr<nsIDocument> doc;
142
  nsCOMPtr<nsIContent> node(do_QueryInterface(aRequestContext));
143
  if (node) {
144
    doc = node->GetOwnerDoc();
145
  }
146
  if (!doc) {
147
    doc = do_QueryInterface(aRequestContext);
148
  }
149
  if (doc) {
150
    IContentSecurityPolicy* csp = doc->GetContentSecurityPolicy();
151
    if (csp) {
152
#ifdef DEBUG
153
      nsAutoString policy;
154
      csp->GetPolicy(policy);
155
      printf(" *** CSPService - shouldProcess - document has policy: %s\n",
156
              ToNewCString(policy));
157
#endif
158
      // obtain the enforcement decision
159
      csp->ShouldProcess(aContentType,
160
                         aContentLocation,
161
                         aRequestOrigin,
162
                         aRequestContext,
163
                         aMimeTypeGuess,
164
                         aExtra,
165
                         aDecision);
166
    }
167
  }
168
#ifdef DEBUG
169
  else {
170
    nsCAutoString uriSpec("None");
171
    aContentLocation->GetSpec(uriSpec);
172
    printf(" *** CSPService - COULD NOT get nsIDocument for location: %s\n",
173
            uriSpec.get());
174
  }
175
#endif
176
  return NS_OK;
177
}
(-)f46e6aee1335 (+67 lines)
Added Link Here 
Added Link Here 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
 *
5
 * The contents of this file are subject to the Mozilla Public License Version
6
 * 1.1 (the "License"); you may not use this file except in compliance with
7
 * the License. You may obtain a copy of the License at
8
 * http://www.mozilla.org/MPL/
9
 *
10
 * Software distributed under the License is distributed on an "AS IS" basis,
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
 * for the specific language governing rights and limitations under the
13
 * License.
14
 *
15
 * The Original Code is mozilla.org code.
16
 *
17
 * The Initial Developer of the Original Code is
18
 * Mozilla Corporation.
19
 * Portions created by the Initial Developer are Copyright (C) 2009
20
 * the Initial Developer. All Rights Reserved.
21
 *
22
 * Contributor(s):
23
 *   Brandon Sterne <bsterne@mozilla.com>
24
 *
25
 * Alternatively, the contents of this file may be used under the terms of
26
 * either of the GNU General Public License Version 2 or later (the "GPL"),
27
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
 * in which case the provisions of the GPL or the LGPL are applicable instead
29
 * of those above. If you wish to allow use of your version of this file only
30
 * under the terms of either the GPL or the LGPL, and not to allow others to
31
 * use your version of this file under the terms of the MPL, indicate your
32
 * decision by deleting the provisions above and replace them with the notice
33
 * and other provisions required by the GPL or the LGPL. If you do not delete
34
 * the provisions above, a recipient may use your version of this file under
35
 * the terms of any one of the MPL, the GPL or the LGPL.
36
 *
37
 * ***** END LICENSE BLOCK ***** */
38
39
#include "nsIGenericFactory.h"
40
41
#include "nsCOMPtr.h"
42
#include "nsXPCOM.h"
43
#include "nsIServiceManager.h"
44
#include "nsICategoryManager.h"
45
46
#include "nsMemory.h"
47
48
#include "nsIContentPolicy.h"
49
#include "nsIObserver.h"
50
51
#define CSPSERVICE_CONTRACTID "@mozilla.org/cspservice;1"
52
#define CSPSERVICE_CID \
53
{ 0x8d2f40b2, 0x4875, 0x4c95, \
54
  { 0x97, 0xd9, 0x3f, 0x7d, 0xca, 0x2c, 0xb4, 0x60 } }
55
56
class CSPService : public nsIContentPolicy
57
{
58
public:
59
  NS_DECL_ISUPPORTS
60
  NS_DECL_NSICONTENTPOLICY
61
  
62
  CSPService();
63
  virtual ~CSPService();
64
65
private:
66
  PRBool mEnabled;
67
};
(-)a/content/base/src/nsDocument.cpp (+74 lines)
Line     Link Here 
 Lines 174-189   static NS_DEFINE_CID(kDOMEventGroupCID, Link Here 
174
#include "mozAutoDocUpdate.h"
174
#include "mozAutoDocUpdate.h"
175
175
176
#ifdef MOZ_SMIL
176
#ifdef MOZ_SMIL
177
#include "nsSMILAnimationController.h"
177
#include "nsSMILAnimationController.h"
178
#include "imgIContainer.h"
178
#include "imgIContainer.h"
179
#include "nsSVGUtils.h"
179
#include "nsSVGUtils.h"
180
#endif // MOZ_SMIL
180
#endif // MOZ_SMIL
181
181
182
// FOR CSP (autogenerated by xpidl)
183
#include "IContentSecurityPolicy.h"
184
182
185
183
#ifdef MOZ_LOGGING
186
#ifdef MOZ_LOGGING
184
// so we can get logging even in release builds
187
// so we can get logging even in release builds
185
#define FORCE_PR_LOG 1
188
#define FORCE_PR_LOG 1
186
#endif
189
#endif
187
#include "prlog.h"
190
#include "prlog.h"
188
191
189
#ifdef PR_LOGGING
192
#ifdef PR_LOGGING
 Lines 2227-2242   nsDocument::StartDocumentLoad(const char Link Here 
2227
    semicolon = start;
2230
    semicolon = start;
2228
    FindCharInReadable(';', semicolon, end);
2231
    FindCharInReadable(';', semicolon, end);
2229
    mContentType = Substring(start, semicolon);
2232
    mContentType = Substring(start, semicolon);
2230
  }
2233
  }
2231
2234
2232
  RetrieveRelevantHeaders(aChannel);
2235
  RetrieveRelevantHeaders(aChannel);
2233
2236
2234
  mChannel = aChannel;
2237
  mChannel = aChannel;
2238
  
2239
// --------------  Initialize CSP
2240
  nsresult rv;
2241
  PRBool system;
2242
  nsIScriptSecurityManager *ssm = nsContentUtils::GetSecurityManager();
2243
  nsAutoString cspHeaderValue;
2244
  nsIAtom* cspHeaderAtom = NS_NewAtom("x-content-security-policy");
2245
2246
  this->GetHeaderData(cspHeaderAtom, cspHeaderValue);
2247
2248
  if(NS_SUCCEEDED(ssm->IsSystemPrincipal(NodePrincipal(), &system)) && system) {
2249
    //only makes sense to register new CSP if this document is not priviliged
2250
    return NS_OK;
2251
  }
2252
2253
  if(cspHeaderValue.IsEmpty()) {
2254
    // no CSP header present
2255
    return NS_OK;
2256
  }
2257
2258
#ifdef DEBUG
2259
  printf(" >> *** DOCUMENT specified CSP header\n");
2260
#endif
2261
2262
  mCSP = do_CreateInstance("@mozilla.org/contentsecuritypolicy;1", &rv);
2263
2264
  if(NS_FAILED(rv)) {
2265
#ifdef DEBUG
2266
    printf("failed to create CSP object: %6x", rv);
2267
#endif
2268
    return rv;
2269
  }
2270
2271
#ifdef DEBUG
2272
  printf(" >> *** CSP Created \"%s\"\n", ToNewCString(cspHeaderValue));
2273
#endif
2274
2275
  // Store the request context for violation reports
2276
  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
2277
  mCSP->ScanRequestData(httpChannel);
2278
2279
  // Start parsing the policy
2280
  nsCOMPtr<nsIURI> chanURI;
2281
  aChannel->GetURI(getter_AddRefs(chanURI));
2282
  mCSP->RefinePolicy(cspHeaderValue, chanURI);
2283
#ifdef DEBUG
2284
  printf(" >> *** CSP policy refined.\n");
2285
#endif
2286
2287
  // Check for frame-ancestor violation
2288
  nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
2289
  if(docShell != NULL) {
2290
    //printf(" >> *** CSP has a docShell\n");
2291
2292
    PRBool safeAncestry = false;
2293
    // PermitsAncestry sends violation reports when necessary
2294
    rv = mCSP->PermitsAncestry(docShell, &safeAncestry);
2295
    if(NS_FAILED(rv)) { return rv; }
2296
2297
    if(!safeAncestry) {
2298
      printf(" >> *** CSP, ancestry is NOT ok.\n");
2299
      // stop!  ERROR page!
2300
      aChannel->Cancel( NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_SECURITY, 99) );
2301
    }
2302
  }
2303
2304
// -------------- CSP initialized
2235
2305
2236
  return NS_OK;
2306
  return NS_OK;
2237
}
2307
}
2238
2308
2239
void
2309
void
2240
nsDocument::StopDocumentLoad()
2310
nsDocument::StopDocumentLoad()
2241
{
2311
{
2242
  if (mParser) {
2312
  if (mParser) {
 Lines 6561-6576   nsDocument::RetrieveRelevantHeaders(nsIC Link Here 
6561
6631
6562
    static const char *const headers[] = {
6632
    static const char *const headers[] = {
6563
      "default-style",
6633
      "default-style",
6564
      "content-style-type",
6634
      "content-style-type",
6565
      "content-language",
6635
      "content-language",
6566
      "content-disposition",
6636
      "content-disposition",
6567
      "refresh",
6637
      "refresh",
6568
      "x-dns-prefetch-control",
6638
      "x-dns-prefetch-control",
6639
      "x-content-security-policy",
6569
      // add more http headers if you need
6640
      // add more http headers if you need
6570
      // XXXbz don't add content-location support without reading bug
6641
      // XXXbz don't add content-location support without reading bug
6571
      // 238654 and its dependencies/dups first.
6642
      // 238654 and its dependencies/dups first.
6572
      0
6643
      0
6573
    };
6644
    };
6574
    
6645
    
6575
    nsCAutoString headerVal;
6646
    nsCAutoString headerVal;
6576
    const char *const *name = headers;
6647
    const char *const *name = headers;
 Lines 6864-6879   nsDocument::CanSavePresentation(nsIReque Link Here 
6864
6935
6865
void
6936
void
6866
nsDocument::Destroy()
6937
nsDocument::Destroy()
6867
{
6938
{
6868
  // The ContentViewer wants to release the document now.  So, tell our content
6939
  // The ContentViewer wants to release the document now.  So, tell our content
6869
  // to drop any references to the document so that it can be destroyed.
6940
  // to drop any references to the document so that it can be destroyed.
6870
  if (mIsGoingAway)
6941
  if (mIsGoingAway)
6871
    return;
6942
    return;
6943
	
6944
  // Take down CSP
6945
  mCSP = 0;
6872
6946
6873
  mIsGoingAway = PR_TRUE;
6947
  mIsGoingAway = PR_TRUE;
6874
6948
6875
  RemovedFromDocShell();
6949
  RemovedFromDocShell();
6876
6950
6877
  PRUint32 i, count = mChildren.ChildCount();
6951
  PRUint32 i, count = mChildren.ChildCount();
6878
  for (i = 0; i < count; ++i) {
6952
  for (i = 0; i < count; ++i) {
6879
    mChildren.ChildAt(i)->DestroyContent();
6953
    mChildren.ChildAt(i)->DestroyContent();
(-)a/docshell/base/nsDocShell.cpp (+8 lines)
Line     Link Here 
 Lines 3559-3574   nsDocShell::DisplayLoadError(nsresult aE Link Here 
3559
        NS_ENSURE_ARG_POINTER(aURI);
3559
        NS_ENSURE_ARG_POINTER(aURI);
3560
        // Get the host
3560
        // Get the host
3561
        nsCAutoString host;
3561
        nsCAutoString host;
3562
        aURI->GetHost(host);
3562
        aURI->GetHost(host);
3563
        CopyUTF8toUTF16(host, formatStrs[0]);
3563
        CopyUTF8toUTF16(host, formatStrs[0]);
3564
        formatStrCount = 1;
3564
        formatStrCount = 1;
3565
        error.AssignLiteral("netTimeout");
3565
        error.AssignLiteral("netTimeout");
3566
    }
3566
    }
3567
    else if ( NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY
3568
             && NS_ERROR_GET_CODE(aError) == 99) {
3569
        // CSP error
3570
        error.AssignLiteral("forbiddenFrameAncestor"); 
3571
        cssClass.AssignLiteral("neterror");
3572
        // TODO: localize this, or at least put the message into a resource
3573
        messageStr.AssignLiteral("CSP Blocked loading of this page because it doesn't trust the page embedding it.");
3574
    } 
3567
    else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) {
3575
    else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) {
3568
        nsCOMPtr<nsINSSErrorsService> nsserr =
3576
        nsCOMPtr<nsINSSErrorsService> nsserr =
3569
            do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
3577
            do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
3570
3578
3571
        PRUint32 errorClass;
3579
        PRUint32 errorClass;
3572
        if (!nsserr ||
3580
        if (!nsserr ||
3573
            NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) {
3581
            NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) {
3574
          errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
3582
          errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
(-)a/layout/build/nsLayoutModule.cpp (-1 / +82 lines)
Line     Link Here 
 Lines 269-284   static nsresult Initialize(nsIModule* aS Link Here 
269
static void Shutdown();
269
static void Shutdown();
270
270
271
#ifdef MOZ_XTF
271
#ifdef MOZ_XTF
272
#include "nsIXTFService.h"
272
#include "nsIXTFService.h"
273
#include "nsIXMLContentBuilder.h"
273
#include "nsIXMLContentBuilder.h"
274
#endif
274
#endif
275
275
276
#include "nsGeolocation.h"
276
#include "nsGeolocation.h"
277
#include "nsCSPService.h"
277
278
278
// Transformiix
279
// Transformiix
279
/* {0C351177-0159-4500-86B0-A219DFDE4258} */
280
/* {0C351177-0159-4500-86B0-A219DFDE4258} */
280
#define TRANSFORMIIX_XPATH1_SCHEME_CID \
281
#define TRANSFORMIIX_XPATH1_SCHEME_CID \
281
{ 0xc351177, 0x159, 0x4500, { 0x86, 0xb0, 0xa2, 0x19, 0xdf, 0xde, 0x42, 0x58 } }
282
{ 0xc351177, 0x159, 0x4500, { 0x86, 0xb0, 0xa2, 0x19, 0xdf, 0xde, 0x42, 0x58 } }
282
283
283
/* 5d5d92cd-6bf8-11d9-bf4a-000a95dc234c */
284
/* 5d5d92cd-6bf8-11d9-bf4a-000a95dc234c */
284
#define TRANSFORMIIX_NODESET_CID \
285
#define TRANSFORMIIX_NODESET_CID \
 Lines 852-867   CreateWindowControllerWithSingletonComma Link Here 
852
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMScriptObjectFactory)
853
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMScriptObjectFactory)
853
NS_GENERIC_FACTORY_CONSTRUCTOR(nsBaseDOMException)
854
NS_GENERIC_FACTORY_CONSTRUCTOR(nsBaseDOMException)
854
855
855
#define NS_GEOLOCATION_SERVICE_CID \
856
#define NS_GEOLOCATION_SERVICE_CID \
856
  { 0x404d02a, 0x1CA, 0xAAAB, { 0x47, 0x62, 0x94, 0x4b, 0x1b, 0xf2, 0xf7, 0xb5 } }
857
  { 0x404d02a, 0x1CA, 0xAAAB, { 0x47, 0x62, 0x94, 0x4b, 0x1b, 0xf2, 0xf7, 0xb5 } }
857
858
858
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsGeolocationService, nsGeolocationService::GetGeolocationService)
859
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsGeolocationService, nsGeolocationService::GetGeolocationService)
859
860
861
static NS_METHOD
862
CSPServiceRegistration(nsIComponentManager *aCompMgr,
863
                       nsIFile *aPath,
864
                       const char *registryLocation,
865
                       const char *componentType,
866
                       const nsModuleComponentInfo *info)
867
{
868
  nsresult rv;
869
  nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv);
870
  if (NS_FAILED(rv))
871
    return rv;
872
873
  nsCOMPtr<nsICategoryManager> catman;
874
  rv = servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID,
875
                                       NS_GET_IID(nsICategoryManager),
876
                                       getter_AddRefs(catman));
877
  if (NS_FAILED(rv))
878
    return rv;
879
  
880
  char* previous = nsnull;
881
  rv = catman->AddCategoryEntry("xpcom-startup",
882
                                "CSPService",
883
                                CSPSERVICE_CONTRACTID,
884
                                PR_TRUE,
885
                                PR_TRUE,
886
                                &previous);
887
  if (previous)
888
    nsMemory::Free(previous);
889
890
  rv = catman->AddCategoryEntry("content-policy",
891
                                "CSPService",
892
                                CSPSERVICE_CONTRACTID,
893
                                PR_TRUE,
894
                                PR_TRUE,
895
                                &previous);
896
  if (previous)
897
    nsMemory::Free(previous);
898
899
  return rv;
900
}
901
902
static NS_METHOD
903
CSPServiceUnregistration(nsIComponentManager *aCompMgr,
904
                         nsIFile *aPath,
905
                         const char *registryLocation,
906
                         const nsModuleComponentInfo *info){
907
  nsresult rv;
908
909
  nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv);
910
  if (NS_FAILED(rv))
911
    return rv;
912
913
  nsCOMPtr<nsICategoryManager> catman;
914
  rv = servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID,
915
                                       NS_GET_IID(nsICategoryManager),
916
                                       getter_AddRefs(catman));
917
  if (NS_FAILED(rv))
918
    return rv;
919
920
  rv = catman->DeleteCategoryEntry("xpcom-startup",
921
                                   "CSPService",
922
                                   PR_TRUE);
923
924
  rv = catman->DeleteCategoryEntry("content-policy",
925
                                   "CSPService",
926
                                   PR_TRUE);
927
928
  return rv;
929
}
930
931
NS_GENERIC_FACTORY_CONSTRUCTOR(CSPService)
932
933
934
860
// The list of components we register
935
// The list of components we register
861
static const nsModuleComponentInfo gComponents[] = {
936
static const nsModuleComponentInfo gComponents[] = {
862
#ifdef DEBUG
937
#ifdef DEBUG
863
  { "Frame utility",
938
  { "Frame utility",
864
    NS_FRAME_UTIL_CID,
939
    NS_FRAME_UTIL_CID,
865
    nsnull,
940
    nsnull,
866
    CreateNewFrameUtil },
941
    CreateNewFrameUtil },
867
  { "Layout debugger",
942
  { "Layout debugger",
 Lines 1461-1477   static const nsModuleComponentInfo gComp Link Here 
1461
      nsTextServicesDocumentConstructor },
1536
      nsTextServicesDocumentConstructor },
1462
#endif
1537
#endif
1463
1538
1464
    { "Geolocation Service",
1539
    { "Geolocation Service",
1465
      NS_GEOLOCATION_SERVICE_CID,
1540
      NS_GEOLOCATION_SERVICE_CID,
1466
      "@mozilla.org/geolocation/service;1",
1541
      "@mozilla.org/geolocation/service;1",
1467
      nsGeolocationServiceConstructor },
1542
      nsGeolocationServiceConstructor },
1468
1543
1469
1544
    { "Content Security Policy Service",
1545
      CSPSERVICE_CID,
1546
      CSPSERVICE_CONTRACTID,
1547
      CSPServiceConstructor,
1548
      CSPServiceRegistration,
1549
      CSPServiceUnregistration
1550
    },
1470
1551
1471
  { "Focus Manager",
1552
  { "Focus Manager",
1472
    NS_FOCUSMANAGER_CID,
1553
    NS_FOCUSMANAGER_CID,
1473
    "@mozilla.org/focus-manager;1",
1554
    "@mozilla.org/focus-manager;1",
1474
    CreateFocusManager },
1555
    CreateFocusManager },
1475
};
1556
};
1476
1557
1477
NS_IMPL_NSGETMODULE_WITH_CTOR(nsLayoutModule, gComponents, Initialize)
1558
NS_IMPL_NSGETMODULE_WITH_CTOR(nsLayoutModule, gComponents, Initialize)

Return to bug 493857