diff --git a/docs/manual/access-control.rst b/docs/manual/access-control.rst index 79e922a98..a9fd89b8a 100644 --- a/docs/manual/access-control.rst +++ b/docs/manual/access-control.rst @@ -1,15 +1,87 @@ .. _access-control: -Access Control System ---------------------- +Embargo and Access Control +-------------------------- -The access controls system allows for a flexible configuration of rules to allow, -block or exclude access to individual urls by longest-prefix match. +The embargo system allows for date-based rules to block access to captures based on their capture dates. + +The access controls system provides additional URL-based rules to allow, block or exclude access to specific URL prefixes or exact URLs. + +The embargo and access control rules are configured per collection. + +Embargo Settings +================ + +The embargo system allows restricting access to all URLs within a collection based on the timestamp of each URL. +Access to these resources is 'embargoed' until the date range is adjusted or the time interval passes. + +The embargo can be used to disallow access to captures based on following criteria: +- Captures before an exact date +- Captures after an exact date +- Captures newer than a time interval +- Captures older than a time interval + +Embargo Before/After Exact Date +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To block access to all captures before or after a specific date, use the ``before`` or ``after`` embargo blocks +with a specific timestamp. + +For example, the following blocks access to all URLs captured before 2020-12-26 in the collection ``embargo-before``:: + + embargo-before: + index_paths: ... + archive_paths: ... + embargo: + before: '20201226' + + +The following blocks access to all URLs captured on or after 2020-12-26 in collection ``embargo-after``:: + + embargo-after: + index_paths: ... + archive_paths: ... + embargo: + after: '20201226' + +Embargo By Time Interval +^^^^^^^^^^^^^^^^^^^^^^^^ + +The embargo can also be set for a relative time interval, consisting of years, months, weeks and/or days. + + +For example, the following blocks access to all URLs newer than 1 year:: + + embargo-newer: + ... + embargo: + newer: + years: 1 + + + +The following blocks access to all URLs older than 1 year, 2 months, 3 weeks and 4 days:: + + embargo-older: + ... + embargo: + older: + years: 1 + months: 2 + weeks: 3 + days: 4 + + +Any combination of years, months, weeks and days can be used (as long as at least one is provided) for the ``newer`` or ``older`` embargo settings. + + +Access Control Settings +======================= Access Control Files (.aclj) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Access controls are set in one or more access control JSON files (.aclj), sorted in reverse alphabetical order. +URL-based access controls are set in one or more access control JSON files (.aclj), sorted in reverse alphabetical order. To determine the best match, a binary search is used (similar to CDXJ) lookup and then the best match is found forward. An .aclj file may look as follows:: @@ -22,6 +94,8 @@ An .aclj file may look as follows:: Each JSON entry contains an ``access`` field and the original ``url`` field that was used to convert to the SURT (if any). +The JSON entry may also contain a ``user`` field, as explained below. + The prefix consists of a SURT key and a ``-`` (currently reserved for a timestamp/date range field to be added later) Given these rules, a user would: @@ -30,19 +104,55 @@ Given these rules, a user would: * would receive a 404 not found error when viewing ``http://httpbin.org/anything`` (exclude) -Access Types: allow, block, exclude -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Access Types: allow, block, exclude, allow_ignore_embargo +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The available access types are as follows: - ``exclude`` - when matched, results are excluded from the index, as if they do not exist. User will receive a 404. - ``block`` - when matched, results are not excluded from the index, marked with ``access: block``, but access to the actual is blocked. User will see a 451 -- ``allow`` - full access to the index and the resource. +- ``allow`` - full access to the index and the resource, but may be overriden by embargo +- ``allow_ignore_embargo`` - full access to the index and resource, overriding any embargo settings The difference between ``exclude`` and ``block`` is that when blocked, the user can be notified that access is blocked, while with exclude, no trace of the resource is presented to the user. -The use of ``allow`` is useful to provide access to more specific resources within a broader block/exclude rule. +The use of ``allow`` is useful to provide access to more specific resources within a broader block/exclude rule, while ``allow_ignore_embargo`` +can be used to override any embargo settings. + +If both are present, the embargo restrictions are checked first and take precedence, unless the ``allow_ignore_embargo`` option is used +to override the embargo. + + +User-Based Access Controls +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The access control rules can further be customized be specifying different permissions for different 'users'. Since pywb does not have a user system, +a special header, ``X-Pywb-ACL-User`` can be used to indicate a specific user. + +This setting is designed to allow a more priveleged user to access additional setting or override an embargo. + +For example, the following access control settings restricts access to ``https://example.com/restricted/`` by default, but allows access for the ``staff`` user:: + + com,example)/restricted - {"access": "allow", "user": "staff"} + com,example)/restricted - {"access": "block"} + + +Combined with the embargo settings, this can also be used to override the embargo for internal organizational users, while keeping the embargo for general access:: + + com,example)/restricted - {"access": "allow_ignore_embargo", "user": "staff"} + com,example)/restricted - {"access": "allow"} + +To make this work, pywb must be running behind an Apache or Nginx system that is configured to set ``X-Pywb-ACL-User: staff`` based on certain settings. + +For example, this header may be set based on IP range, or based on password authentication. + +Further examples of how to set this header will be provided in the deployments section. + +**Note: Do not use the user-based rules without configuring proper authentication on an Apache or Nginx frontend to set or remove this header, otherwise the 'X-Pywb-ACL-User' can easily be faked.** + +See the :ref:`config-acl-header` section in Usage for examples on how to configure this header. + Access Error Messages ^^^^^^^^^^^^^^^^^^^^^ @@ -73,6 +183,11 @@ The URL supplied can be a URL or a SURT prefix. If a SURT is supplied, it is use wb-manager acl add com, allow +A specific user for user-based rules can also be specified, for example to add ``allow_ignore_embargo`` for user ``staff`` only, run:: + + wb-manager acl add http://httpbin.org/anything/something allow_ignore_embargo staff + + By default, access control rules apply to a prefix of a given URL or SURT. To have the rule apply only to the exact match, use:: @@ -136,6 +251,20 @@ set merge-sorted to find the best match (very similar to the CDXJ index lookup). Note: It might make sense to separate ``allows.aclj`` and ``blocks.aclj`` into individual files for organizational reasons, but there is no specific need to keep more than one access control files. +Finally, ACLJ and embargo settings combined for the same collection might look as follows:: + + collections: + test: + ... + embargo: + newer: + days: 366 + + acl_paths: + - ./path/to/allows.aclj + - ./path/to/blocks.aclj + + Default Access ^^^^^^^^^^^^^^ diff --git a/docs/manual/cdxserver_api.rst b/docs/manual/cdxserver_api.rst index 54ea7332f..66b5108ef 100644 --- a/docs/manual/cdxserver_api.rst +++ b/docs/manual/cdxserver_api.rst @@ -182,7 +182,7 @@ the following modifiers: ``fields`` -^^^^^^ +^^^^^^^^^^ The ``fields`` param can be used to specify which fields to include in the output. The standard available fields are usually: ``urlkey``, diff --git a/docs/manual/usage.rst b/docs/manual/usage.rst index 7ee73df2c..d322ad20d 100644 --- a/docs/manual/usage.rst +++ b/docs/manual/usage.rst @@ -293,6 +293,50 @@ Then, in your config, simply include: The configuration assumes uwsgi is started with ``uwsgi uwsgi.ini`` +.. _config-acl-header: + +Configuring Access Control Header +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :ref:`access-control` system allows users to be granted different access settings based on the value of an ACL header, ``X-pywb-ACL-user``. + +The header can be set via Nginx or Apache to grant custom access priviliges based on IP address, password, or other combination of rules. + +For example, to set the value of the header to ``staff`` if the IP of the request is from designated local IP ranges (127.0.0.1, 192.168.1.0/24), the following settings can be added to the configs: + +For Nginx:: + + geo $acl_user { + # ensure user is set to empty by default + default ""; + + # optional: add IP ranges to allow privileged access + 127.0.0.1 "staff"; + 192.168.0.0/24 "staff"; + } + + ... + location /wayback/ { + ... + uwsgi_param HTTP_X_PYWB_ACL_USER $acl_user; + } + + +For Apache:: + + + RequestHeader set X-Pywb-ACL-User staff + + # ensure header is cleared if no match + + RequestHeader set X-Pywb-ACL-User "" + + +} + + + + Running on Subdirectory Path ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/pywb/apps/rewriterapp.py b/pywb/apps/rewriterapp.py index 66b456072..9df559cd9 100644 --- a/pywb/apps/rewriterapp.py +++ b/pywb/apps/rewriterapp.py @@ -704,6 +704,8 @@ def _do_req(self, inputreq, wb_url, kwargs, skip_record): headers = {'Content-Length': str(len(req_data)), 'Content-Type': 'application/request'} + headers.update(inputreq.warcserver_headers) + if skip_record: headers['Recorder-Skip'] = '1' diff --git a/pywb/manager/aclmanager.py b/pywb/manager/aclmanager.py index d4ce218bb..3305b9124 100644 --- a/pywb/manager/aclmanager.py +++ b/pywb/manager/aclmanager.py @@ -12,7 +12,7 @@ class ACLManager(CollectionsManager): SURT_RX = re.compile('([^:.]+[,)])+') - VALID_ACCESS = ('allow', 'block', 'exclude') + VALID_ACCESS = ('allow', 'block', 'exclude', 'allow_ignore_embargo') DEFAULT_FILE = 'access-rules.aclj' @@ -167,9 +167,9 @@ def add_rule(self, r): :param argparse.Namespace r: The argparse namespace representing the rule to be added :rtype: None """ - return self._add_rule(r.url, r.access, r.exact_match) + return self._add_rule(r.url, r.access, r.exact_match, r.user) - def _add_rule(self, url, access, exact_match=False): + def _add_rule(self, url, access, exact_match=False, user=None): """Adds an rule to the acl file :param str url: The URL for the rule @@ -185,12 +185,14 @@ def _add_rule(self, url, access, exact_match=False): acl['timestamp'] = '-' acl['access'] = access acl['url'] = url + if user: + acl['user'] = user i = 0 replace = False for rule in self.rules: - if acl['urlkey'] == rule['urlkey'] and acl['timestamp'] == rule['timestamp']: + if acl['urlkey'] == rule['urlkey'] and acl['timestamp'] == rule['timestamp'] and acl.get('user') == rule.get('user'): replace = True break @@ -255,7 +257,7 @@ def remove_rule(self, r): i = 0 urlkey = self.to_key(r.url, r.exact_match) for rule in self.rules: - if urlkey == rule['urlkey']: + if urlkey == rule['urlkey'] and r.user == rule.get('user'): acl = self.rules.pop(i) print('Removed Rule:') self.print_rule(acl) @@ -285,7 +287,7 @@ def find_match(self, r): :rtype: None """ access_checker = AccessChecker(self.acl_file, '') - rule = access_checker.find_access_rule(r.url) + rule = access_checker.find_access_rule(r.url, acl_user=r.user) print('Matched rule:') print('') @@ -344,15 +346,18 @@ def command(name, *args, **kwargs): else: op.add_argument(arg) + if kwargs.get('user_opt'): + op.add_argument('-u', '--user') + if kwargs.get('exact_opt'): op.add_argument('-e', '--exact-match', action='store_true', default=False) op.set_defaults(acl_func=kwargs['func']) - command('add', 'coll_name', 'url', 'access', func=cls.add_rule, exact_opt=True) - command('remove', 'coll_name', 'url', func=cls.remove_rule, exact_opt=True) + command('add', 'coll_name', 'url', 'access', func=cls.add_rule, exact_opt=True, user_opt=True) + command('remove', 'coll_name', 'url', func=cls.remove_rule, exact_opt=True, user_opt=True) command('list', 'coll_name', func=cls.list_rules) command('validate', 'coll_name', func=cls.validate_save) - command('match', 'coll_name', 'url', 'default_access', func=cls.find_match) + command('match', 'coll_name', 'url', 'default_access', func=cls.find_match, user_opt=True) command('importtxt', 'coll_name', 'filename', 'access', func=cls.add_excludes) diff --git a/pywb/rewrite/rewriteinputreq.py b/pywb/rewrite/rewriteinputreq.py index 11d12d92f..6eab1ce08 100644 --- a/pywb/rewrite/rewriteinputreq.py +++ b/pywb/rewrite/rewriteinputreq.py @@ -26,6 +26,7 @@ def __init__(self, env, urlkey, url, rewriter): self.url = url self.rewriter = rewriter self.extra_cookie = None + self.warcserver_headers = {} is_proxy = ('wsgiprox.proxy_host' in env) @@ -82,6 +83,11 @@ def get_req_headers(self): elif name in ('HTTP_IF_MODIFIED_SINCE', 'HTTP_IF_UNMODIFIED_SINCE'): continue + elif name == 'HTTP_X_PYWB_ACL_USER': + name = name[5:].title().replace('_', '-') + self.warcserver_headers[name] = value + continue + elif name == 'HTTP_X_FORWARDED_PROTO': name = 'X-Forwarded-Proto' if self.splits: diff --git a/pywb/static/wombat.js b/pywb/static/wombat.js index a0177650e..26fc7f74e 100644 --- a/pywb/static/wombat.js +++ b/pywb/static/wombat.js @@ -18,4 +18,4 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -(function(){function FuncMap(){this._map=[]}function ensureNumber(maybeNumber){try{switch(typeof maybeNumber){case"number":case"bigint":return maybeNumber;}var converted=Number(maybeNumber);return isNaN(converted)?null:converted}catch(e){}return null}function addToStringTagToClass(clazz,tag){typeof self.Symbol!=="undefined"&&typeof self.Symbol.toStringTag!=="undefined"&&Object.defineProperty(clazz.prototype,self.Symbol.toStringTag,{value:tag,enumerable:false})}function autobind(clazz){for(var prop,propValue,proto=clazz.__proto__||clazz.constructor.prototype||clazz.prototype,clazzProps=Object.getOwnPropertyNames(proto),len=clazzProps.length,i=0;i=0){var fnMapping=this._map.splice(idx,1);return fnMapping[0][1]}return null},FuncMap.prototype.map=function(param){for(var i=0;i0&&afw.preserveMedia(media)})},AutoFetcher.prototype.terminate=function(){this.worker.terminate()},AutoFetcher.prototype.justFetch=function(urls){this.worker.postMessage({type:"fetch-all",values:urls})},AutoFetcher.prototype.fetchAsPage=function(url,originalUrl,title){if(url){var headers={"X-Wombat-History-Page":originalUrl};if(title){var encodedTitle=encodeURIComponent(title.trim());title&&(headers["X-Wombat-History-Title"]=encodedTitle)}var fetchData={url:url,options:{headers:headers,cache:"no-store"}};this.justFetch([fetchData])}},AutoFetcher.prototype.postMessage=function(msg,deferred){if(deferred){var afWorker=this;return void Promise.resolve().then(function(){afWorker.worker.postMessage(msg)})}this.worker.postMessage(msg)},AutoFetcher.prototype.preserveSrcset=function(srcset,mod){this.postMessage({type:"values",srcset:{value:srcset,mod:mod,presplit:true}},true)},AutoFetcher.prototype.preserveDataSrcset=function(elem){this.postMessage({type:"values",srcset:{value:elem.dataset.srcset,mod:this.rwMod(elem),presplit:false}},true)},AutoFetcher.prototype.preserveMedia=function(media){this.postMessage({type:"values",media:media},true)},AutoFetcher.prototype.getSrcset=function(elem){return this.wombat.wb_getAttribute?this.wombat.wb_getAttribute.call(elem,"srcset"):elem.getAttribute("srcset")},AutoFetcher.prototype.rwMod=function(elem){switch(elem.tagName){case"SOURCE":return elem.parentElement&&elem.parentElement.tagName==="PICTURE"?"im_":"oe_";case"IMG":return"im_";}return"oe_"},AutoFetcher.prototype.extractFromLocalDoc=function(){var afw=this;Promise.resolve().then(function(){for(var msg={type:"values",context:{docBaseURI:document.baseURI}},media=[],i=0,sheets=document.styleSheets;i=0},Wombat.prototype.isString=function(arg){return arg!=null&&Object.getPrototypeOf(arg)===String.prototype},Wombat.prototype.isSavedSrcSrcset=function(elem){switch(elem.tagName){case"IMG":case"VIDEO":case"AUDIO":return true;case"SOURCE":if(!elem.parentElement)return false;switch(elem.parentElement.tagName){case"PICTURE":case"VIDEO":case"AUDIO":return true;default:return false;}default:return false;}},Wombat.prototype.isSavedDataSrcSrcset=function(elem){return!!(elem.dataset&&elem.dataset.srcset!=null)&&this.isSavedSrcSrcset(elem)},Wombat.prototype.isHostUrl=function(str){if(str.indexOf("www.")===0)return true;var matches=str.match(this.hostnamePortRe);return!!(matches&&matches[0].length<64)||(matches=str.match(this.ipPortRe),!!matches&&matches[0].length<64)},Wombat.prototype.isArgumentsObj=function(maybeArgumentsObj){if(!maybeArgumentsObj||typeof maybeArgumentsObj.toString!=="function")return false;try{return this.utilFns.objToString.call(maybeArgumentsObj)==="[object Arguments]"}catch(e){return false}},Wombat.prototype.deproxyArrayHandlingArgumentsObj=function(maybeArgumentsObj){if(!maybeArgumentsObj||maybeArgumentsObj instanceof NodeList||!maybeArgumentsObj.length)return maybeArgumentsObj;for(var args=this.isArgumentsObj(maybeArgumentsObj)?new Array(maybeArgumentsObj.length):maybeArgumentsObj,i=0;i=0)||scriptType.indexOf("text/template")>=0)},Wombat.prototype.skipWrapScriptTextBasedOnText=function(text){if(!text||text.indexOf(this.WB_ASSIGN_FUNC)>=0||text.indexOf("<")===0)return true;for(var override_props=["window","self","document","location","top","parent","frames","opener"],i=0;i=0)return false;return true},Wombat.prototype.nodeHasChildren=function(node){if(!node)return false;if(typeof node.hasChildNodes==="function")return node.hasChildNodes();var kids=node.children||node.childNodes;return!!kids&&kids.length>0},Wombat.prototype.rwModForElement=function(elem,attrName){if(!elem)return undefined;var mod="mp_";if(!(elem.tagName==="LINK"&&attrName==="href")){var maybeMod=this.tagToMod[elem.tagName];maybeMod!=null&&(mod=maybeMod[attrName])}else if(elem.rel){var relV=elem.rel.trim().toLowerCase(),asV=this.wb_getAttribute.call(elem,"as");if(asV&&this.linkTagMods.linkRelToAs[relV]!=null){var asMods=this.linkTagMods.linkRelToAs[relV];mod=asMods[asV.toLowerCase()]}else this.linkTagMods[relV]!=null&&(mod=this.linkTagMods[relV])}return mod},Wombat.prototype.removeWBOSRC=function(elem){elem.tagName!=="SCRIPT"||elem.__$removedWBOSRC$__||(elem.hasAttribute("__wb_orig_src")&&elem.removeAttribute("__wb_orig_src"),elem.__$removedWBOSRC$__=true)},Wombat.prototype.retrieveWBOSRC=function(elem){if(elem.tagName==="SCRIPT"&&!elem.__$removedWBOSRC$__){var maybeWBOSRC;return maybeWBOSRC=this.wb_getAttribute?this.wb_getAttribute.call(elem,"__wb_orig_src"):elem.getAttribute("__wb_orig_src"),maybeWBOSRC==null&&(elem.__$removedWBOSRC$__=true),maybeWBOSRC}return undefined},Wombat.prototype.wrapScriptTextJsProxy=function(scriptText){return"var _____WB$wombat$assign$function_____ = function(name) {return (self._wb_wombat && self._wb_wombat.local_init && self._wb_wombat.local_init(name)) || self[name]; };\nif (!self.__WB_pmw) { self.__WB_pmw = function(obj) { this.__WB_source = obj; return this; } }\n{\nlet window = _____WB$wombat$assign$function_____(\"window\");\nlet self = _____WB$wombat$assign$function_____(\"self\");\nlet document = _____WB$wombat$assign$function_____(\"document\");\nlet location = _____WB$wombat$assign$function_____(\"location\");\nlet top = _____WB$wombat$assign$function_____(\"top\");\nlet parent = _____WB$wombat$assign$function_____(\"parent\");\nlet frames = _____WB$wombat$assign$function_____(\"frames\");\nlet opener = _____WB$wombat$assign$function_____(\"opener\");\n"+scriptText.replace(this.DotPostMessageRe,".__WB_pmw(self.window)$1")+"\n\n}"},Wombat.prototype.watchElem=function(elem,func){if(!this.$wbwindow.MutationObserver)return false;var m=new this.$wbwindow.MutationObserver(function(records,observer){for(var r,i=0;i"},Wombat.prototype.getFinalUrl=function(useRel,mod,url){var prefix=useRel?this.wb_rel_prefix:this.wb_abs_prefix;return mod==null&&(mod=this.wb_info.mod),this.wb_info.is_live||(prefix+=this.wb_info.wombat_ts),prefix+=mod,prefix[prefix.length-1]!=="/"&&(prefix+="/"),prefix+url},Wombat.prototype.resolveRelUrl=function(url,doc){var docObj=doc||this.$wbwindow.document,parser=this.makeParser(docObj.baseURI,docObj),hash=parser.href.lastIndexOf("#"),href=hash>=0?parser.href.substring(0,hash):parser.href,lastslash=href.lastIndexOf("/");return parser.href=lastslash>=0&&lastslash!==href.length-1?href.substring(0,lastslash+1)+url:href+url,parser.href},Wombat.prototype.extractOriginalURL=function(rewrittenUrl){if(!rewrittenUrl)return"";if(this.wb_is_proxy)return rewrittenUrl;var rwURLString=rewrittenUrl.toString(),url=rwURLString;if(this.startsWithOneOf(url,this.IGNORE_PREFIXES))return url;var start;start=this.startsWith(url,this.wb_abs_prefix)?this.wb_abs_prefix.length:this.wb_rel_prefix&&this.startsWith(url,this.wb_rel_prefix)?this.wb_rel_prefix.length:this.wb_rel_prefix?1:0;var index=url.indexOf("/http",start);return index<0&&(index=url.indexOf("///",start)),index<0&&(index=url.indexOf("/blob:",start)),index<0&&(index=url.indexOf("/about:blank",start)),index>=0?url=url.substr(index+1):(index=url.indexOf(this.wb_replay_prefix),index>=0&&(url=url.substr(index+this.wb_replay_prefix.length)),url.length>4&&url.charAt(2)==="_"&&url.charAt(3)==="/"&&(url=url.substr(4)),url!==rwURLString&&!this.startsWithOneOf(url,this.VALID_PREFIXES)&&!this.startsWith(url,"blob:")&&(url=this.wb_orig_scheme+url)),rwURLString.charAt(0)==="/"&&rwURLString.charAt(1)!=="/"&&this.startsWith(url,this.wb_orig_origin)&&(url=url.substr(this.wb_orig_origin.length)),this.startsWith(url,this.REL_PREFIX)?this.wb_info.wombat_scheme+":"+url:url},Wombat.prototype.makeParser=function(maybeRewrittenURL,doc){var originalURL=this.extractOriginalURL(maybeRewrittenURL),docElem=doc;return doc||(this.$wbwindow.location.href==="about:blank"&&this.$wbwindow.opener?docElem=this.$wbwindow.opener.document:docElem=this.$wbwindow.document),this._makeURLParser(originalURL,docElem)},Wombat.prototype._makeURLParser=function(url,docElem){try{return new this.$wbwindow.URL(url,docElem.baseURI)}catch(e){}var p=docElem.createElement("a");return p._no_rewrite=true,p.href=url,p},Wombat.prototype.defProp=function(obj,prop,setFunc,getFunc,enumerable){var existingDescriptor=Object.getOwnPropertyDescriptor(obj,prop);if(existingDescriptor&&!existingDescriptor.configurable)return false;if(!getFunc)return false;var descriptor={configurable:true,enumerable:enumerable||false,get:getFunc};setFunc&&(descriptor.set=setFunc);try{return Object.defineProperty(obj,prop,descriptor),true}catch(e){return console.warn("Failed to redefine property %s",prop,e.message),false}},Wombat.prototype.defGetterProp=function(obj,prop,getFunc,enumerable){var existingDescriptor=Object.getOwnPropertyDescriptor(obj,prop);if(existingDescriptor&&!existingDescriptor.configurable)return false;if(!getFunc)return false;try{return Object.defineProperty(obj,prop,{configurable:true,enumerable:enumerable||false,get:getFunc}),true}catch(e){return console.warn("Failed to redefine property %s",prop,e.message),false}},Wombat.prototype.getOrigGetter=function(obj,prop){var orig_getter;if(obj.__lookupGetter__&&(orig_getter=obj.__lookupGetter__(prop)),!orig_getter&&Object.getOwnPropertyDescriptor){var props=Object.getOwnPropertyDescriptor(obj,prop);props&&(orig_getter=props.get)}return orig_getter},Wombat.prototype.getOrigSetter=function(obj,prop){var orig_setter;if(obj.__lookupSetter__&&(orig_setter=obj.__lookupSetter__(prop)),!orig_setter&&Object.getOwnPropertyDescriptor){var props=Object.getOwnPropertyDescriptor(obj,prop);props&&(orig_setter=props.set)}return orig_setter},Wombat.prototype.getAllOwnProps=function(obj){for(var ownProps=[],props=Object.getOwnPropertyNames(obj),i=0;i "+final_href),actualLocation.href=final_href}}},Wombat.prototype.checkLocationChange=function(wombatLoc,isTop){var locType=typeof wombatLoc,actual_location=isTop?this.$wbwindow.__WB_replay_top.location:this.$wbwindow.location;locType==="string"?this.updateLocation(wombatLoc,actual_location.href,actual_location):locType==="object"&&this.updateLocation(wombatLoc.href,wombatLoc._orig_href,actual_location)},Wombat.prototype.checkAllLocations=function(){return!this.wb_wombat_updating&&void(this.wb_wombat_updating=true,this.checkLocationChange(this.$wbwindow.WB_wombat_location,false),this.$wbwindow.WB_wombat_location!=this.$wbwindow.__WB_replay_top.WB_wombat_location&&this.checkLocationChange(this.$wbwindow.__WB_replay_top.WB_wombat_location,true),this.wb_wombat_updating=false)},Wombat.prototype.proxyToObj=function(source){if(source)try{var proxyRealObj=source.__WBProxyRealObj__;if(proxyRealObj)return proxyRealObj}catch(e){}return source},Wombat.prototype.objToProxy=function(obj){if(obj)try{var maybeWbProxy=obj._WB_wombat_obj_proxy;if(maybeWbProxy)return maybeWbProxy}catch(e){}return obj},Wombat.prototype.defaultProxyGet=function(obj,prop,ownProps,fnCache){switch(prop){case"__WBProxyRealObj__":return obj;case"location":case"WB_wombat_location":return obj.WB_wombat_location;case"_WB_wombat_obj_proxy":return obj._WB_wombat_obj_proxy;case"__WB_pmw":case"WB_wombat_eval":case this.WB_ASSIGN_FUNC:case this.WB_CHECK_THIS_FUNC:return obj[prop];case"origin":return obj.WB_wombat_location.origin;case"constructor":if(obj.constructor===Window)return obj.constructor;}var retVal=obj[prop],type=typeof retVal;if(type==="function"&&ownProps.indexOf(prop)!==-1){switch(prop){case"requestAnimationFrame":case"cancelAnimationFrame":{if(!this.isNativeFunction(retVal))return retVal;break}}var cachedFN=fnCache[prop];return cachedFN&&cachedFN.original===retVal||(cachedFN={original:retVal,boundFn:retVal.bind(obj)},fnCache[prop]=cachedFN),cachedFN.boundFn}return type==="object"&&retVal&&retVal._WB_wombat_obj_proxy?(retVal instanceof Window&&this.initNewWindowWombat(retVal),retVal._WB_wombat_obj_proxy):retVal},Wombat.prototype.setLoc=function(loc,originalURL){var parser=this.makeParser(originalURL,loc.ownerDocument);loc._orig_href=originalURL,loc._parser=parser;var href=parser.href;loc._hash=parser.hash,loc._href=href,loc._host=parser.host,loc._hostname=parser.hostname,loc._origin=parser.origin?parser.host?parser.origin:"null":parser.protocol+"//"+parser.hostname+(parser.port?":"+parser.port:""),loc._pathname=parser.pathname,loc._port=parser.port,loc._protocol=parser.protocol,loc._search=parser.search,Object.defineProperty||(loc.href=href,loc.hash=parser.hash,loc.host=loc._host,loc.hostname=loc._hostname,loc.origin=loc._origin,loc.pathname=loc._pathname,loc.port=loc._port,loc.protocol=loc._protocol,loc.search=loc._search)},Wombat.prototype.makeGetLocProp=function(prop,origGetter){var wombat=this;return function newGetLocProp(){if(this._no_rewrite)return origGetter.call(this,prop);var curr_orig_href=origGetter.call(this,"href");return prop==="href"?wombat.extractOriginalURL(curr_orig_href):prop==="ancestorOrigins"?[]:(this._orig_href!==curr_orig_href&&wombat.setLoc(this,curr_orig_href),this["_"+prop])}},Wombat.prototype.makeSetLocProp=function(prop,origSetter,origGetter){var wombat=this;return function newSetLocProp(value){if(this._no_rewrite)return origSetter.call(this,prop,value);if(this["_"+prop]!==value){if(this["_"+prop]=value,!this._parser){var href=origGetter.call(this);this._parser=wombat.makeParser(href,this.ownerDocument)}var rel=false;prop==="href"&&typeof value==="string"&&value&&(value[0]==="."?value=wombat.resolveRelUrl(value,this.ownerDocument):value[0]==="/"&&(value.length<=1||value[1]!=="/")&&(rel=true,value=WB_wombat_location.origin+value));try{this._parser[prop]=value}catch(e){console.log("Error setting "+prop+" = "+value)}prop==="hash"?(value=this._parser[prop],origSetter.call(this,"hash",value)):(rel=rel||value===this._parser.pathname,value=wombat.rewriteUrl(this._parser.href,rel),origSetter.call(this,"href",value))}}},Wombat.prototype.styleReplacer=function(match,n1,n2,n3,offset,string){return n1+this.rewriteUrl(n2)+n3},Wombat.prototype.domConstructorErrorChecker=function(thisObj,what,args,numRequiredArgs){var errorMsg,needArgs=typeof numRequiredArgs==="number"?numRequiredArgs:1;if(thisObj instanceof Window?errorMsg="Failed to construct '"+what+"': Please use the 'new' operator, this DOM object constructor cannot be called as a function.":args&&args.length=0)return url;if(url.indexOf(this.wb_rel_prefix)===0&&url.indexOf("http")>1){var scheme_sep=url.indexOf(":/");return scheme_sep>0&&url[scheme_sep+2]!=="/"?url.substring(0,scheme_sep+2)+"/"+url.substring(scheme_sep+2):url}return this.getFinalUrl(true,mod,this.wb_orig_origin+url)}url.charAt(0)==="."&&(url=this.resolveRelUrl(url,doc));var prefix=this.startsWithOneOf(url.toLowerCase(),this.VALID_PREFIXES);if(prefix){var orig_host=this.$wbwindow.__WB_replay_top.location.host,orig_protocol=this.$wbwindow.__WB_replay_top.location.protocol,prefix_host=prefix+orig_host+"/";if(this.startsWith(url,prefix_host)){if(this.startsWith(url,this.wb_replay_prefix))return url;var curr_scheme=orig_protocol+"//",path=url.substring(prefix_host.length),rebuild=false;return path.indexOf(this.wb_rel_prefix)<0&&url.indexOf("/static/")<0&&(path=this.getFinalUrl(true,mod,WB_wombat_location.origin+"/"+path),rebuild=true),prefix!==curr_scheme&&prefix!==this.REL_PREFIX&&(rebuild=true),rebuild&&(url=useRel?"":curr_scheme+orig_host,path&&path[0]!=="/"&&(url+="/"),url+=path),url}return this.getFinalUrl(useRel,mod,url)}return prefix=this.startsWithOneOf(url,this.BAD_PREFIXES),prefix?this.getFinalUrl(useRel,mod,this.extractOriginalURL(url)):this.isHostUrl(url)&&!this.startsWith(url,originalLoc.host+"/")?this.getFinalUrl(useRel,mod,this.wb_orig_scheme+url):url},Wombat.prototype.rewriteUrl=function(url,useRel,mod,doc){var rewritten=this.rewriteUrl_(url,useRel,mod,doc);return this.debug_rw&&(url===rewritten?console.log("NOT REWRITTEN "+url):console.log("REWRITE: "+url+" -> "+rewritten)),rewritten},Wombat.prototype.performAttributeRewrite=function(elem,name,value,absUrlOnly){switch(name){case"innerHTML":case"outerHTML":return this.rewriteHtml(value);case"filter":return this.rewriteInlineStyle(value);case"style":return this.rewriteStyle(value);case"srcset":return this.rewriteSrcset(value,elem);}if(absUrlOnly&&!this.startsWithOneOf(value,this.VALID_PREFIXES))return value;var mod=this.rwModForElement(elem,name);return this.wbUseAFWorker&&this.WBAutoFetchWorker&&this.isSavedDataSrcSrcset(elem)&&this.WBAutoFetchWorker.preserveDataSrcset(elem),this.rewriteUrl(value,false,mod,elem.ownerDocument)},Wombat.prototype.rewriteAttr=function(elem,name,absUrlOnly){var changed=false;if(!elem||!elem.getAttribute||elem._no_rewrite||elem["_"+name])return changed;var value=this.wb_getAttribute.call(elem,name);if(!value||this.startsWith(value,"javascript:"))return changed;var new_value=this.performAttributeRewrite(elem,name,value,absUrlOnly);return new_value!==value&&(this.removeWBOSRC(elem),this.wb_setAttribute.call(elem,name,new_value),changed=true),changed},Wombat.prototype.noExceptRewriteStyle=function(style){try{return this.rewriteStyle(style)}catch(e){return style}},Wombat.prototype.rewriteStyle=function(style){if(!style)return style;var value=style;return typeof style==="object"&&(value=style.toString()),typeof value==="string"?value.replace(this.STYLE_REGEX,this.styleReplacer).replace(this.IMPORT_REGEX,this.styleReplacer).replace(this.no_wombatRe,""):value},Wombat.prototype.rewriteSrcset=function(value,elem){if(!value)return"";for(var split=value.split(this.srcsetRe),values=[],mod=this.rwModForElement(elem,"srcset"),i=0;i=0){var JS="javascript:";new_value="javascript:window.parent._wb_wombat.initNewWindowWombat(window);"+value.substr(11)}return new_value||(new_value=this.rewriteUrl(value,false,this.rwModForElement(elem,attrName))),new_value!==value&&(this.wb_setAttribute.call(elem,attrName,new_value),true)},Wombat.prototype.rewriteScript=function(elem){if(elem.hasAttribute("src")||!elem.textContent||!this.$wbwindow.Proxy)return this.rewriteAttr(elem,"src");if(this.skipWrapScriptBasedOnType(elem.type))return false;var text=elem.textContent.trim();return!this.skipWrapScriptTextBasedOnText(text)&&(elem.textContent=this.wrapScriptTextJsProxy(text),true)},Wombat.prototype.rewriteSVGElem=function(elem){var changed=this.rewriteAttr(elem,"filter");return changed=this.rewriteAttr(elem,"style")||changed,changed=this.rewriteAttr(elem,"xlink:href")||changed,changed=this.rewriteAttr(elem,"href")||changed,changed=this.rewriteAttr(elem,"src")||changed,changed},Wombat.prototype.rewriteElem=function(elem){var changed=false;if(!elem)return changed;if(elem instanceof SVGElement)changed=this.rewriteSVGElem(elem);else switch(elem.tagName){case"META":var maybeCSP=this.wb_getAttribute.call(elem,"http-equiv");maybeCSP&&maybeCSP.toLowerCase()==="content-security-policy"&&(this.wb_setAttribute.call(elem,"http-equiv","_"+maybeCSP),changed=true);break;case"STYLE":var new_content=this.rewriteStyle(elem.textContent);elem.textContent!==new_content&&(elem.textContent=new_content,changed=true,this.wbUseAFWorker&&this.WBAutoFetchWorker&&elem.sheet!=null&&this.WBAutoFetchWorker.deferredSheetExtraction(elem.sheet));break;case"LINK":changed=this.rewriteAttr(elem,"href"),this.wbUseAFWorker&&elem.rel==="stylesheet"&&this._addEventListener(elem,"load",this.utilFns.wbSheetMediaQChecker);break;case"IMG":changed=this.rewriteAttr(elem,"src"),changed=this.rewriteAttr(elem,"srcset")||changed,changed=this.rewriteAttr(elem,"style")||changed,this.wbUseAFWorker&&this.WBAutoFetchWorker&&elem.dataset.srcset&&this.WBAutoFetchWorker.preserveDataSrcset(elem);break;case"OBJECT":if(this.wb_info.isSW&&elem.parentElement&&elem.getAttribute("type")==="application/pdf"){for(var iframe=this.$wbwindow.document.createElement("IFRAME"),i=0;i0;)for(var child,children=rewriteQ.shift(),i=0;i"+rwString+"","text/html");if(!inner_doc||!this.nodeHasChildren(inner_doc.head)||!inner_doc.head.children[0].content)return rwString;var template=inner_doc.head.children[0];if(template._no_rewrite=true,this.recurseRewriteElem(template.content)){var new_html=template.innerHTML;if(checkEndTag){var first_elem=template.content.children&&template.content.children[0];if(first_elem){var end_tag="";this.endsWith(new_html,end_tag)&&!this.endsWith(rwString.toLowerCase(),end_tag)&&(new_html=new_html.substring(0,new_html.length-end_tag.length))}else if(rwString[0]!=="<"||rwString[rwString.length-1]!==">")return this.write_buff+=rwString,undefined}return new_html}return rwString},Wombat.prototype.rewriteHtmlFull=function(string,checkEndTag){var inner_doc=new DOMParser().parseFromString(string,"text/html");if(!inner_doc)return string;for(var changed=false,i=0;i=0)inner_doc.documentElement._no_rewrite=true,new_html=this.reconstructDocType(inner_doc.doctype)+inner_doc.documentElement.outerHTML;else{inner_doc.head._no_rewrite=true,inner_doc.body._no_rewrite=true;var headHasKids=this.nodeHasChildren(inner_doc.head),bodyHasKids=this.nodeHasChildren(inner_doc.body);if(new_html=(headHasKids?inner_doc.head.outerHTML:"")+(bodyHasKids?inner_doc.body.outerHTML:""),checkEndTag)if(inner_doc.all.length>3){var end_tag="";this.endsWith(new_html,end_tag)&&!this.endsWith(string.toLowerCase(),end_tag)&&(new_html=new_html.substring(0,new_html.length-end_tag.length))}else if(string[0]!=="<"||string[string.length-1]!==">")return void(this.write_buff+=string);new_html=this.reconstructDocType(inner_doc.doctype)+new_html}return new_html}return string},Wombat.prototype.rewriteInlineStyle=function(orig){var decoded;try{decoded=decodeURIComponent(orig)}catch(e){decoded=orig}if(decoded!==orig){var parts=this.rewriteStyle(decoded).split(",",2);return parts[0]+","+encodeURIComponent(parts[1])}return this.rewriteStyle(orig)},Wombat.prototype.rewriteCookie=function(cookie){var wombat=this,rwCookie=cookie.replace(this.wb_abs_prefix,"").replace(this.wb_rel_prefix,"");return rwCookie=rwCookie.replace(this.cookie_domain_regex,function(m,m1){var message={domain:m1,cookie:rwCookie,wb_type:"cookie"};return wombat.sendTopMessage(message,true),wombat.$wbwindow.location.hostname.indexOf(".")>=0&&!wombat.IP_RX.test(wombat.$wbwindow.location.hostname)?"Domain=."+wombat.$wbwindow.location.hostname:""}).replace(this.cookie_path_regex,function(m,m1){var rewritten=wombat.rewriteUrl(m1);return rewritten.indexOf(wombat.wb_curr_host)===0&&(rewritten=rewritten.substring(wombat.wb_curr_host.length)),"Path="+rewritten}),wombat.$wbwindow.location.protocol!=="https:"&&(rwCookie=rwCookie.replace("secure","")),rwCookie.replace(",|",",")},Wombat.prototype.rewriteWorker=function(workerUrl){if(!workerUrl)return workerUrl;var isBlob=workerUrl.indexOf("blob:")===0,isJS=workerUrl.indexOf("javascript:")===0;if(!isBlob&&!isJS){if(!this.startsWithOneOf(workerUrl,this.VALID_PREFIXES)&&!this.startsWith(workerUrl,"/")&&!this.startsWithOneOf(workerUrl,this.BAD_PREFIXES)){var rurl=this.resolveRelUrl(workerUrl,this.$wbwindow.document);return this.rewriteUrl(rurl,false,"wkr_",this.$wbwindow.document)}return this.rewriteUrl(workerUrl,false,"wkr_",this.$wbwindow.document)}var workerCode=isJS?workerUrl.replace("javascript:",""):null;if(isBlob){var x=new XMLHttpRequest;this.utilFns.XHRopen.call(x,"GET",workerUrl,false),this.utilFns.XHRsend.call(x),workerCode=x.responseText.replace(this.workerBlobRe,"").replace(this.rmCheckThisInjectRe,"this")}if(this.wb_info.static_prefix||this.wb_info.ww_rw_script){var originalURL=this.$wbwindow.document.baseURI,ww_rw=this.wb_info.ww_rw_script||this.wb_info.static_prefix+"wombatWorkers.js",rw="(function() { self.importScripts('"+ww_rw+"'); new WBWombat({'prefix': '"+this.wb_abs_prefix+"', 'prefixMod': '"+this.wb_abs_prefix+"wkrf_/', 'originalURL': '"+originalURL+"'}); })();";workerCode=rw+workerCode}var blob=new Blob([workerCode],{type:"application/javascript"});return URL.createObjectURL(blob)},Wombat.prototype.rewriteTextNodeFn=function(fnThis,originalFn,argsObj){var args,deproxiedThis=this.proxyToObj(fnThis);if(argsObj.length>0&&deproxiedThis.parentElement&&deproxiedThis.parentElement.tagName==="STYLE"){args=new Array(argsObj.length);var dataIndex=argsObj.length-1;dataIndex===2?(args[0]=argsObj[0],args[1]=argsObj[1]):dataIndex===1&&(args[0]=argsObj[0]),args[dataIndex]=this.rewriteStyle(argsObj[dataIndex])}else args=argsObj;return originalFn.__WB_orig_apply?originalFn.__WB_orig_apply(deproxiedThis,args):originalFn.apply(deproxiedThis,args)},Wombat.prototype.rewriteDocWriteWriteln=function(fnThis,originalFn,argsObj){var string,thisObj=this.proxyToObj(fnThis),argLen=argsObj.length;if(argLen===0)return originalFn.call(thisObj);string=argLen===1?argsObj[0]:Array.prototype.join.call(argsObj,"");var new_buff=this.rewriteHtml(string,true),res=originalFn.call(thisObj,new_buff);return this.initNewWindowWombat(thisObj.defaultView),res},Wombat.prototype.rewriteChildNodeFn=function(fnThis,originalFn,argsObj){var thisObj=this.proxyToObj(fnThis);if(argsObj.length===0)return originalFn.call(thisObj);var newArgs=this.rewriteElementsInArguments(argsObj);return originalFn.__WB_orig_apply?originalFn.__WB_orig_apply(thisObj,newArgs):originalFn.apply(thisObj,newArgs)},Wombat.prototype.rewriteInsertAdjHTMLOrElemArgs=function(fnThis,originalFn,position,textOrElem,rwHTML){var fnThisObj=this.proxyToObj(fnThis);return fnThisObj._no_rewrite?originalFn.call(fnThisObj,position,textOrElem):rwHTML?originalFn.call(fnThisObj,position,this.rewriteHtml(textOrElem)):(this.rewriteElemComplete(textOrElem),originalFn.call(fnThisObj,position,textOrElem))},Wombat.prototype.rewriteSetTimeoutInterval=function(fnThis,originalFn,argsObj){var rw=this.isString(argsObj[0]),args=rw?new Array(argsObj.length):argsObj;if(rw){args[0]=this.$wbwindow.Proxy?this.wrapScriptTextJsProxy(argsObj[0]):argsObj[0].replace(/\blocation\b/g,"WB_wombat_$&");for(var i=1;i0&&cssStyleValueOverride(this.$wbwindow.CSSStyleValue,"parse"),this.$wbwindow.CSSStyleValue.parseAll&&this.$wbwindow.CSSStyleValue.parseAll.toString().indexOf("[native code]")>0&&cssStyleValueOverride(this.$wbwindow.CSSStyleValue,"parseAll")}if(this.$wbwindow.CSSKeywordValue&&this.$wbwindow.CSSKeywordValue.prototype){var oCSSKV=this.$wbwindow.CSSKeywordValue;this.$wbwindow.CSSKeywordValue=function(CSSKeywordValue_){return function CSSKeywordValue(cssValue){return wombat.domConstructorErrorChecker(this,"CSSKeywordValue",arguments),new CSSKeywordValue_(wombat.rewriteStyle(cssValue))}}(this.$wbwindow.CSSKeywordValue),this.$wbwindow.CSSKeywordValue.prototype=oCSSKV.prototype,Object.defineProperty(this.$wbwindow.CSSKeywordValue.prototype,"constructor",{value:this.$wbwindow.CSSKeywordValue}),addToStringTagToClass(this.$wbwindow.CSSKeywordValue,"CSSKeywordValue")}if(this.$wbwindow.StylePropertyMap&&this.$wbwindow.StylePropertyMap.prototype){var originalSet=this.$wbwindow.StylePropertyMap.prototype.set;this.$wbwindow.StylePropertyMap.prototype.set=function set(){if(arguments.length<=1)return originalSet.__WB_orig_apply?originalSet.__WB_orig_apply(this,arguments):originalSet.apply(this,arguments);var newArgs=new Array(arguments.length);newArgs[0]=arguments[0];for(var i=1;i")&&(array[0]=wombat.rewriteHtml(array[0]),options.type="text/html"),new Blob_(array,options)}}(this.$wbwindow.Blob),this.$wbwindow.Blob.prototype=orig_blob.prototype}},Wombat.prototype.initDocTitleOverride=function(){var orig_get_title=this.getOrigGetter(this.$wbwindow.document,"title"),orig_set_title=this.getOrigSetter(this.$wbwindow.document,"title"),wombat=this,set_title=function title(value){var res=orig_set_title.call(this,value),message={wb_type:"title",title:value};return wombat.sendTopMessage(message),res};this.defProp(this.$wbwindow.document,"title",set_title,orig_get_title)},Wombat.prototype.initFontFaceOverride=function(){if(this.$wbwindow.FontFace){var wombat=this,origFontFace=this.$wbwindow.FontFace;this.$wbwindow.FontFace=function(FontFace_){return function FontFace(family,source,descriptors){wombat.domConstructorErrorChecker(this,"FontFace",arguments,2);var rwSource=source;return source!=null&&(typeof source==="string"?rwSource=wombat.rewriteInlineStyle(source):rwSource=wombat.rewriteInlineStyle(source.toString())),new FontFace_(family,rwSource,descriptors)}}(this.$wbwindow.FontFace),this.$wbwindow.FontFace.prototype=origFontFace.prototype,Object.defineProperty(this.$wbwindow.FontFace.prototype,"constructor",{value:this.$wbwindow.FontFace}),addToStringTagToClass(this.$wbwindow.FontFace,"FontFace")}},Wombat.prototype.initFixedRatio=function(){try{this.$wbwindow.devicePixelRatio=1}catch(e){}if(Object.defineProperty)try{Object.defineProperty(this.$wbwindow,"devicePixelRatio",{value:1,writable:false})}catch(e){}},Wombat.prototype.initPaths=function(wbinfo){wbinfo.wombat_opts=wbinfo.wombat_opts||{},this.wb_info=wbinfo,this.wb_opts=wbinfo.wombat_opts,this.wb_replay_prefix=wbinfo.prefix,this.wb_is_proxy=wbinfo.proxy_magic||!this.wb_replay_prefix,this.wb_info.top_host=this.wb_info.top_host||"*",this.wb_curr_host=this.$wbwindow.location.protocol+"//"+this.$wbwindow.location.host,this.wb_orig_scheme=wbinfo.wombat_scheme+"://",this.wb_orig_origin=this.wb_orig_scheme+wbinfo.wombat_host,this.wb_abs_prefix=this.wb_replay_prefix,this.wb_capture_date_part=!wbinfo.is_live&&wbinfo.wombat_ts?"/"+wbinfo.wombat_ts+"/":"",this.initBadPrefixes(this.wb_replay_prefix)},Wombat.prototype.initSeededRandom=function(seed){this.$wbwindow.Math.seed=parseInt(seed);var wombat=this;this.$wbwindow.Math.random=function random(){return wombat.$wbwindow.Math.seed=(wombat.$wbwindow.Math.seed*9301+49297)%233280,wombat.$wbwindow.Math.seed/233280}},Wombat.prototype.initHistoryOverrides=function(){this.overrideHistoryFunc("pushState"),this.overrideHistoryFunc("replaceState");var wombat=this;this.$wbwindow.addEventListener("popstate",function(event){wombat.sendHistoryUpdate(wombat.$wbwindow.WB_wombat_location.href,wombat.$wbwindow.document.title)})},Wombat.prototype.initHTTPOverrides=function(){var wombat=this;if(!this.wb_info.isSW&&this.$wbwindow.XMLHttpRequest.prototype.open){var origXMLHttpOpen=this.$wbwindow.XMLHttpRequest.prototype.open;this.utilFns.XHRopen=origXMLHttpOpen,this.utilFns.XHRsend=this.$wbwindow.XMLHttpRequest.prototype.send,this.$wbwindow.XMLHttpRequest.prototype.open=function open(method,url,async,user,password){var rwURL=this._no_rewrite?url:wombat.rewriteUrl(url),openAsync=true;async==null||async||(openAsync=false),origXMLHttpOpen.call(this,method,rwURL,openAsync,user,password),wombat.startsWith(rwURL,"data:")||this.setRequestHeader("X-Pywb-Requested-With","XMLHttpRequest")}}if(this.overridePropExtract(this.$wbwindow.XMLHttpRequest.prototype,"responseURL"),this.wb_info.isSW){function jsonToQueryString(json){if(typeof json==="string")try{json=JSON.parse(json)}catch(e){json={}}var q=new URLSearchParams;try{JSON.stringify(json,function(k,v){return["object","function"].includes(typeof v)||q.set(k,v),v})}catch(e){}return"__wb_post=1&"+q.toString()}var origOpen=this.$wbwindow.XMLHttpRequest.prototype.open,origSetRequestHeader=this.$wbwindow.XMLHttpRequest.prototype.setRequestHeader,origSend=this.$wbwindow.XMLHttpRequest.prototype.send;this.utilFns.XHRopen=origOpen,this.utilFns.XHRsend=origSend,this.$wbwindow.XMLHttpRequest.prototype.open=function(){this.__WB_xhr_open_arguments=arguments,this.__WB_xhr_headers=new Headers},this.$wbwindow.XMLHttpRequest.prototype.setRequestHeader=function(name,value){this.__WB_xhr_headers.set(name,value)};var wombat=this;this.$wbwindow.XMLHttpRequest.prototype.send=function(value){if(this.__WB_xhr_open_arguments[0]==="POST"){var contentType=this.__WB_xhr_headers.get("Content-Type");typeof value==="string"&&contentType==="application/x-www-form-urlencoded"||value instanceof URLSearchParams?(this.__WB_xhr_open_arguments[0]="GET",this.__WB_xhr_open_arguments[1]+=(this.__WB_xhr_open_arguments[1].indexOf("?")>0?"&":"?")+value.toString(),value=null):contentType==="application/json"&&(this.__WB_xhr_open_arguments[0]="GET",this.__WB_xhr_open_arguments[1]+=(this.__WB_xhr_open_arguments[1].indexOf("?")>0?"&":"?")+jsonToQueryString(value),value=null)}if(this.__WB_xhr_open_arguments.length>2&&(this.__WB_xhr_open_arguments[2]=true),this._no_rewrite||(this.__WB_xhr_open_arguments[1]=wombat.rewriteUrl(this.__WB_xhr_open_arguments[1])),origOpen.apply(this,this.__WB_xhr_open_arguments),!wombat.startsWith(this.__WB_xhr_open_arguments[1],"data:")){for(const[name,value]of this.__WB_xhr_headers.entries())origSetRequestHeader.call(this,name,value);origSetRequestHeader.call(this,"X-Pywb-Requested-With","XMLHttpRequest")}origSend.call(this,value)}}if(this.$wbwindow.fetch){var orig_fetch=this.$wbwindow.fetch;this.$wbwindow.fetch=function fetch(input,init_opts){var rwInput=input,inputType=typeof input;if(inputType==="string")rwInput=wombat.rewriteUrl(input);else if(inputType==="object"&&input.url){var new_url=wombat.rewriteUrl(input.url);new_url!==input.url&&(rwInput=new Request(new_url,init_opts))}else inputType==="object"&&input.href&&(rwInput=wombat.rewriteUrl(input.href));if(init_opts||(init_opts={}),init_opts.credentials===undefined)try{init_opts.credentials="include"}catch(e){}return orig_fetch.call(wombat.proxyToObj(this),rwInput,init_opts)}}if(this.$wbwindow.Request&&this.$wbwindow.Request.prototype){var orig_request=this.$wbwindow.Request;this.$wbwindow.Request=function(Request_){return function Request(input,init_opts){wombat.domConstructorErrorChecker(this,"Request",arguments);var newInitOpts=init_opts||{},newInput=input,inputType=typeof input;switch(inputType){case"string":newInput=wombat.rewriteUrl(input);break;case"object":if(newInput=input,input.url){var new_url=wombat.rewriteUrl(input.url);new_url!==input.url&&(newInput=new Request_(new_url,input))}else input.href&&(newInput=wombat.rewriteUrl(input.toString(),true));}return newInitOpts.credentials="include",new Request_(newInput,newInitOpts)}}(this.$wbwindow.Request),this.$wbwindow.Request.prototype=orig_request.prototype,Object.defineProperty(this.$wbwindow.Request.prototype,"constructor",{value:this.$wbwindow.Request})}if(this.$wbwindow.Response&&this.$wbwindow.Response.prototype){var originalRedirect=this.$wbwindow.Response.prototype.redirect;this.$wbwindow.Response.prototype.redirect=function redirect(url,status){var rwURL=wombat.rewriteUrl(url,true,null,wombat.$wbwindow.document);return originalRedirect.call(this,rwURL,status)}}if(this.$wbwindow.EventSource&&this.$wbwindow.EventSource.prototype){var origEventSource=this.$wbwindow.EventSource;this.$wbwindow.EventSource=function(EventSource_){return function EventSource(url,configuration){wombat.domConstructorErrorChecker(this,"EventSource",arguments);var rwURL=url;return url!=null&&(rwURL=wombat.rewriteUrl(url)),new EventSource_(rwURL,configuration)}}(this.$wbwindow.EventSource),this.$wbwindow.EventSource.prototype=origEventSource.prototype,Object.defineProperty(this.$wbwindow.EventSource.prototype,"constructor",{value:this.$wbwindow.EventSource}),addToStringTagToClass(this.$wbwindow.EventSource,"EventSource")}if(this.$wbwindow.WebSocket&&this.$wbwindow.WebSocket.prototype){var origWebSocket=this.$wbwindow.WebSocket;this.$wbwindow.WebSocket=function(WebSocket_){return function WebSocket(url,configuration){wombat.domConstructorErrorChecker(this,"WebSocket",arguments);var rwURL=url;return url!=null&&(rwURL=wombat.rewriteWSURL(url)),new WebSocket_(rwURL,configuration)}}(this.$wbwindow.WebSocket),this.$wbwindow.WebSocket.prototype=origWebSocket.prototype,Object.defineProperty(this.$wbwindow.WebSocket.prototype,"constructor",{value:this.$wbwindow.WebSocket}),addToStringTagToClass(this.$wbwindow.WebSocket,"WebSocket")}},Wombat.prototype.initElementGetSetAttributeOverride=function(){if(!this.wb_opts.skip_setAttribute&&this.$wbwindow.Element&&this.$wbwindow.Element.prototype){var wombat=this,ElementProto=this.$wbwindow.Element.prototype;if(ElementProto.setAttribute){var orig_setAttribute=ElementProto.setAttribute;ElementProto._orig_setAttribute=orig_setAttribute,ElementProto.setAttribute=function setAttribute(name,value){var rwValue=value;if(name&&typeof rwValue==="string"){var lowername=name.toLowerCase();if(this.tagName==="LINK"&&lowername==="href"&&rwValue.indexOf("data:text/css")===0)rwValue=wombat.rewriteInlineStyle(value);else if(lowername==="style")rwValue=wombat.rewriteStyle(value);else if(lowername==="srcset")rwValue=wombat.rewriteSrcset(value,this);else{var shouldRW=wombat.shouldRewriteAttr(this.tagName,lowername);shouldRW&&(wombat.removeWBOSRC(this),!this._no_rewrite&&(rwValue=wombat.rewriteUrl(value,false,wombat.rwModForElement(this,lowername))))}}return orig_setAttribute.call(this,name,rwValue)}}if(ElementProto.getAttribute){var orig_getAttribute=ElementProto.getAttribute;this.wb_getAttribute=orig_getAttribute,ElementProto.getAttribute=function getAttribute(name){var result=orig_getAttribute.call(this,name);if(result===null)return result;var lowerName=name;if(name&&(lowerName=name.toLowerCase()),wombat.shouldRewriteAttr(this.tagName,lowerName)){var maybeWBOSRC=wombat.retrieveWBOSRC(this);return maybeWBOSRC?maybeWBOSRC:wombat.extractOriginalURL(result)}return wombat.startsWith(lowerName,"data-")&&wombat.startsWithOneOf(result,wombat.wb_prefixes)?wombat.extractOriginalURL(result):result}}}},Wombat.prototype.initSvgImageOverrides=function(){if(this.$wbwindow.SVGImageElement){var svgImgProto=this.$wbwindow.SVGImageElement.prototype,orig_getAttr=svgImgProto.getAttribute,orig_getAttrNS=svgImgProto.getAttributeNS,orig_setAttr=svgImgProto.setAttribute,orig_setAttrNS=svgImgProto.setAttributeNS,wombat=this;svgImgProto.getAttribute=function getAttribute(name){var value=orig_getAttr.call(this,name);return name.indexOf("xlink:href")>=0||name==="href"?wombat.extractOriginalURL(value):value},svgImgProto.getAttributeNS=function getAttributeNS(ns,name){var value=orig_getAttrNS.call(this,ns,name);return name.indexOf("xlink:href")>=0||name==="href"?wombat.extractOriginalURL(value):value},svgImgProto.setAttribute=function setAttribute(name,value){var rwValue=value;return(name.indexOf("xlink:href")>=0||name==="href")&&(rwValue=wombat.rewriteUrl(value)),orig_setAttr.call(this,name,rwValue)},svgImgProto.setAttributeNS=function setAttributeNS(ns,name,value){var rwValue=value;return(name.indexOf("xlink:href")>=0||name==="href")&&(rwValue=wombat.rewriteUrl(value)),orig_setAttrNS.call(this,ns,name,rwValue)}}},Wombat.prototype.initCreateElementNSFix=function(){if(this.$wbwindow.document.createElementNS&&this.$wbwindow.Document.prototype.createElementNS){var orig_createElementNS=this.$wbwindow.document.createElementNS,wombat=this,createElementNS=function createElementNS(namespaceURI,qualifiedName){return orig_createElementNS.call(wombat.proxyToObj(this),wombat.extractOriginalURL(namespaceURI),qualifiedName)};this.$wbwindow.Document.prototype.createElementNS=createElementNS,this.$wbwindow.document.createElementNS=createElementNS}},Wombat.prototype.initInsertAdjacentElementHTMLOverrides=function(){var Element=this.$wbwindow.Element;if(Element&&Element.prototype){var elementProto=Element.prototype,rewriteFn=this.rewriteInsertAdjHTMLOrElemArgs;if(elementProto.insertAdjacentHTML){var origInsertAdjacentHTML=elementProto.insertAdjacentHTML;elementProto.insertAdjacentHTML=function insertAdjacentHTML(position,text){return rewriteFn(this,origInsertAdjacentHTML,position,text,true)}}if(elementProto.insertAdjacentElement){var origIAdjElem=elementProto.insertAdjacentElement;elementProto.insertAdjacentElement=function insertAdjacentElement(position,element){return rewriteFn(this,origIAdjElem,position,element,false)}}}},Wombat.prototype.initDomOverride=function(){var Node=this.$wbwindow.Node;if(Node&&Node.prototype){var rewriteFn=this.rewriteNodeFuncArgs;if(Node.prototype.appendChild){var originalAppendChild=Node.prototype.appendChild;Node.prototype.appendChild=function appendChild(newNode,oldNode){return rewriteFn(this,originalAppendChild,newNode,oldNode)}}if(Node.prototype.insertBefore){var originalInsertBefore=Node.prototype.insertBefore;Node.prototype.insertBefore=function insertBefore(newNode,oldNode){return rewriteFn(this,originalInsertBefore,newNode,oldNode)}}if(Node.prototype.replaceChild){var originalReplaceChild=Node.prototype.replaceChild;Node.prototype.replaceChild=function replaceChild(newNode,oldNode){return rewriteFn(this,originalReplaceChild,newNode,oldNode)}}this.overridePropToProxy(Node.prototype,"ownerDocument"),this.overridePropToProxy(this.$wbwindow.HTMLHtmlElement.prototype,"parentNode"),this.overridePropToProxy(this.$wbwindow.Event.prototype,"target")}this.$wbwindow.Element&&this.$wbwindow.Element.prototype&&(this.overrideParentNodeAppendPrepend(this.$wbwindow.Element),this.overrideChildNodeInterface(this.$wbwindow.Element,false)),this.$wbwindow.DocumentFragment&&this.$wbwindow.DocumentFragment.prototype&&this.overrideParentNodeAppendPrepend(this.$wbwindow.DocumentFragment)},Wombat.prototype.initDocOverrides=function($document){if(Object.defineProperty){this.overrideReferrer($document),this.defGetterProp($document,"origin",function origin(){return this.WB_wombat_location.origin}),this.defGetterProp(this.$wbwindow,"origin",function origin(){return this.WB_wombat_location.origin});var wombat=this,domain_setter=function domain(val){var loc=this.WB_wombat_location;loc&&wombat.endsWith(loc.hostname,val)&&(this.__wb_domain=val)},domain_getter=function domain(){return this.__wb_domain||this.WB_wombat_location.hostname};this.defProp($document,"domain",domain_setter,domain_getter)}},Wombat.prototype.initDocWriteOpenCloseOverride=function(){if(this.$wbwindow.DOMParser){var DocumentProto=this.$wbwindow.Document.prototype,$wbDocument=this.$wbwindow.document,docWriteWritelnRWFn=this.rewriteDocWriteWriteln,orig_doc_write=$wbDocument.write,new_write=function write(){return docWriteWritelnRWFn(this,orig_doc_write,arguments)};$wbDocument.write=new_write,DocumentProto.write=new_write;var orig_doc_writeln=$wbDocument.writeln,new_writeln=function writeln(){return docWriteWritelnRWFn(this,orig_doc_writeln,arguments)};$wbDocument.writeln=new_writeln,DocumentProto.writeln=new_writeln;var wombat=this,orig_doc_open=$wbDocument.open,new_open=function open(){var res,thisObj=wombat.proxyToObj(this);if(arguments.length===3){var rwUrl=wombat.rewriteUrl(arguments[0],false,"mp_");res=orig_doc_open.call(thisObj,rwUrl,arguments[1],arguments[2]),wombat.initNewWindowWombat(res,arguments[0])}else res=orig_doc_open.call(thisObj),wombat.initNewWindowWombat(thisObj.defaultView);return res};$wbDocument.open=new_open,DocumentProto.open=new_open;var originalClose=$wbDocument.close,newClose=function close(){var thisObj=wombat.proxyToObj(this);return wombat.initNewWindowWombat(thisObj.defaultView),originalClose.__WB_orig_apply?originalClose.__WB_orig_apply(thisObj,arguments):originalClose.apply(thisObj,arguments)};$wbDocument.close=newClose,DocumentProto.close=newClose;var oBodyGetter=this.getOrigGetter(DocumentProto,"body"),oBodySetter=this.getOrigSetter(DocumentProto,"body");oBodyGetter&&oBodySetter&&this.defProp(DocumentProto,"body",function body(newBody){return newBody&&(newBody instanceof HTMLBodyElement||newBody instanceof HTMLFrameSetElement)&&wombat.rewriteElemComplete(newBody),oBodySetter.call(wombat.proxyToObj(this),newBody)},oBodyGetter)}},Wombat.prototype.initIframeWombat=function(iframe){var win;win=iframe._get_contentWindow?iframe._get_contentWindow.call(iframe):iframe.contentWindow;try{if(!win||win===this.$wbwindow||win._skip_wombat||win._wb_wombat)return}catch(e){return}var src=iframe.src;this.initNewWindowWombat(win,src)},Wombat.prototype.initNewWindowWombat=function(win,src){var fullWombat=false;if(win&&!win._wb_wombat){if((!src||src===""||this.startsWithOneOf(src,["about:blank","javascript:"]))&&(fullWombat=true),!fullWombat&&this.wb_info.isSW){var origURL=this.extractOriginalURL(src);(origURL==="about:blank"||origURL.startsWith("srcdoc:")||origURL.startsWith("blob:"))&&(fullWombat=true)}if(fullWombat){var wombat=new Wombat(win,this.wb_info);win._wb_wombat=wombat.wombatInit()}else this.initProtoPmOrigin(win),this.initPostMessageOverride(win),this.initMessageEventOverride(win),this.initCheckThisFunc(win)}},Wombat.prototype.initTimeoutIntervalOverrides=function(){var rewriteFn=this.rewriteSetTimeoutInterval;if(this.$wbwindow.setTimeout&&!this.$wbwindow.setTimeout.__$wbpatched$__){var originalSetTimeout=this.$wbwindow.setTimeout;this.$wbwindow.setTimeout=function setTimeout(){return rewriteFn(this,originalSetTimeout,arguments)},this.$wbwindow.setTimeout.__$wbpatched$__=true}if(this.$wbwindow.setInterval&&!this.$wbwindow.setInterval.__$wbpatched$__){var originalSetInterval=this.$wbwindow.setInterval;this.$wbwindow.setInterval=function setInterval(){return rewriteFn(this,originalSetInterval,arguments)},this.$wbwindow.setInterval.__$wbpatched$__=true}},Wombat.prototype.initWorkerOverrides=function(){var wombat=this;if(this.$wbwindow.Worker&&!this.$wbwindow.Worker._wb_worker_overriden){var orig_worker=this.$wbwindow.Worker;this.$wbwindow.Worker=function(Worker_){return function Worker(url,options){return wombat.domConstructorErrorChecker(this,"Worker",arguments),new Worker_(wombat.rewriteWorker(url),options)}}(orig_worker),this.$wbwindow.Worker.prototype=orig_worker.prototype,Object.defineProperty(this.$wbwindow.Worker.prototype,"constructor",{value:this.$wbwindow.Worker}),this.$wbwindow.Worker._wb_worker_overriden=true}if(this.$wbwindow.SharedWorker&&!this.$wbwindow.SharedWorker.__wb_sharedWorker_overriden){var oSharedWorker=this.$wbwindow.SharedWorker;this.$wbwindow.SharedWorker=function(SharedWorker_){return function SharedWorker(url,options){return wombat.domConstructorErrorChecker(this,"SharedWorker",arguments),new SharedWorker_(wombat.rewriteWorker(url),options)}}(oSharedWorker),this.$wbwindow.SharedWorker.prototype=oSharedWorker.prototype,Object.defineProperty(this.$wbwindow.SharedWorker.prototype,"constructor",{value:this.$wbwindow.SharedWorker}),this.$wbwindow.SharedWorker.__wb_sharedWorker_overriden=true}if(this.$wbwindow.ServiceWorkerContainer&&this.$wbwindow.ServiceWorkerContainer.prototype&&this.$wbwindow.ServiceWorkerContainer.prototype.register){var orig_register=this.$wbwindow.ServiceWorkerContainer.prototype.register;this.$wbwindow.ServiceWorkerContainer.prototype.register=function register(scriptURL,options){var newScriptURL=new URL(scriptURL,wombat.$wbwindow.document.baseURI).href,mod=wombat.getPageUnderModifier();return options&&options.scope?options.scope=wombat.rewriteUrl(options.scope,false,mod):options={scope:wombat.rewriteUrl("/",false,mod)},orig_register.call(this,wombat.rewriteUrl(newScriptURL,false,"sw_"),options)}}if(this.$wbwindow.Worklet&&this.$wbwindow.Worklet.prototype&&this.$wbwindow.Worklet.prototype.addModule&&!this.$wbwindow.Worklet.__wb_workerlet_overriden){var oAddModule=this.$wbwindow.Worklet.prototype.addModule;this.$wbwindow.Worklet.prototype.addModule=function addModule(moduleURL,options){var rwModuleURL=wombat.rewriteUrl(moduleURL,false,"js_");return oAddModule.call(this,rwModuleURL,options)},this.$wbwindow.Worklet.__wb_workerlet_overriden=true}},Wombat.prototype.initLocOverride=function(loc,oSetter,oGetter){if(Object.defineProperty)for(var prop,i=0;i=0&&props.splice(foundInx,1);return props}})}catch(e){console.log(e)}},Wombat.prototype.initHashChange=function(){if(this.$wbwindow.__WB_top_frame){var wombat=this,receive_hash_change=function receive_hash_change(event){if(event.data&&event.data.from_top){var message=event.data.message;message.wb_type&&(message.wb_type!=="outer_hashchange"||wombat.$wbwindow.location.hash==message.hash||(wombat.$wbwindow.location.hash=message.hash))}},send_hash_change=function send_hash_change(){var message={wb_type:"hashchange",hash:wombat.$wbwindow.location.hash};wombat.sendTopMessage(message)};this.$wbwindow.addEventListener("message",receive_hash_change),this.$wbwindow.addEventListener("hashchange",send_hash_change)}},Wombat.prototype.initPostMessageOverride=function($wbwindow){if($wbwindow.postMessage&&!$wbwindow.__orig_postMessage){var orig=$wbwindow.postMessage,wombat=this;$wbwindow.__orig_postMessage=orig;var postmessage_rewritten=function postMessage(message,targetOrigin,transfer,from_top){var from,src_id,this_obj=wombat.proxyToObj(this);if(this_obj.__WB_source&&this_obj.__WB_source.WB_wombat_location){var source=this_obj.__WB_source;if(from=source.WB_wombat_location.origin,this_obj.__WB_win_id||(this_obj.__WB_win_id={},this_obj.__WB_counter=0),!source.__WB_id){var id=this_obj.__WB_counter;source.__WB_id=id+source.WB_wombat_location.href,this_obj.__WB_counter+=1}this_obj.__WB_win_id[source.__WB_id]=source,src_id=source.__WB_id,this_obj.__WB_source=undefined}else from=window.WB_wombat_location.origin;var to_origin=targetOrigin;to_origin===this_obj.location.origin&&(to_origin=from);var new_message={from:from,to_origin:to_origin,src_id:src_id,message:message,from_top:from_top};if(targetOrigin!=="*"){if(this_obj.location.origin==="null"||this_obj.location.origin==="")return;targetOrigin=this_obj.location.origin}return orig.call(this_obj,new_message,targetOrigin,transfer)};$wbwindow.postMessage=postmessage_rewritten,$wbwindow.Window.prototype.postMessage=postmessage_rewritten;var eventTarget=null;eventTarget=$wbwindow.EventTarget&&$wbwindow.EventTarget.prototype?$wbwindow.EventTarget.prototype:$wbwindow;var _oAddEventListener=eventTarget.addEventListener;eventTarget.addEventListener=function addEventListener(type,listener,useCapture){var rwListener,obj=wombat.proxyToObj(this);if(type==="message"?rwListener=wombat.message_listeners.add_or_get(listener,function(){return wrapEventListener(listener,obj,wombat)}):type==="storage"?wombat.storage_listeners.add_or_get(listener,function(){return wrapSameOriginEventListener(listener,obj)}):rwListener=listener,rwListener)return _oAddEventListener.call(obj,type,rwListener,useCapture)};var _oRemoveEventListener=eventTarget.removeEventListener;eventTarget.removeEventListener=function removeEventListener(type,listener,useCapture){var rwListener,obj=wombat.proxyToObj(this);if(type==="message"?rwListener=wombat.message_listeners.remove(listener):type==="storage"?wombat.storage_listeners.remove(listener):rwListener=listener,rwListener)return _oRemoveEventListener.call(obj,type,rwListener,useCapture)};var override_on_prop=function(onevent,wrapperFN){var orig_setter=wombat.getOrigSetter($wbwindow,onevent),setter=function(value){this["__orig_"+onevent]=value;var obj=wombat.proxyToObj(this),listener=value?wrapperFN(value,obj,wombat):value;return orig_setter.call(obj,listener)},getter=function(){return this["__orig_"+onevent]};wombat.defProp($wbwindow,onevent,setter,getter)};override_on_prop("onmessage",wrapEventListener),override_on_prop("onstorage",wrapSameOriginEventListener)}},Wombat.prototype.initMessageEventOverride=function($wbwindow){!$wbwindow.MessageEvent||$wbwindow.MessageEvent.prototype.__extended||(this.addEventOverride("target"),this.addEventOverride("srcElement"),this.addEventOverride("currentTarget"),this.addEventOverride("eventPhase"),this.addEventOverride("path"),this.overridePropToProxy($wbwindow.MessageEvent.prototype,"source"),$wbwindow.MessageEvent.prototype.__extended=true)},Wombat.prototype.initUIEventsOverrides=function(){this.overrideAnUIEvent("UIEvent"),this.overrideAnUIEvent("MouseEvent"),this.overrideAnUIEvent("TouchEvent"),this.overrideAnUIEvent("FocusEvent"),this.overrideAnUIEvent("KeyboardEvent"),this.overrideAnUIEvent("WheelEvent"),this.overrideAnUIEvent("InputEvent"),this.overrideAnUIEvent("CompositionEvent")},Wombat.prototype.initOpenOverride=function(){var orig=this.$wbwindow.open;this.$wbwindow.Window.prototype.open&&(orig=this.$wbwindow.Window.prototype.open);var wombat=this,open_rewritten=function open(strUrl,strWindowName,strWindowFeatures){var rwStrUrl=wombat.rewriteUrl(strUrl,false,""),res=orig.call(wombat.proxyToObj(this),rwStrUrl,strWindowName,strWindowFeatures);return wombat.initNewWindowWombat(res,strUrl),res};this.$wbwindow.open=open_rewritten,this.$wbwindow.Window.prototype.open&&(this.$wbwindow.Window.prototype.open=open_rewritten);for(var i=0;i=0){var fnMapping=this._map.splice(idx,1);return fnMapping[0][1]}return null},FuncMap.prototype.map=function(param){for(var i=0;i0&&afw.preserveMedia(media)})},AutoFetcher.prototype.terminate=function(){this.worker.terminate()},AutoFetcher.prototype.justFetch=function(urls){this.worker.postMessage({type:"fetch-all",values:urls})},AutoFetcher.prototype.fetchAsPage=function(url,originalUrl,title){if(url){var headers={"X-Wombat-History-Page":originalUrl};if(title){var encodedTitle=encodeURIComponent(title.trim());title&&(headers["X-Wombat-History-Title"]=encodedTitle)}var fetchData={url:url,options:{headers:headers,cache:"no-store"}};this.justFetch([fetchData])}},AutoFetcher.prototype.postMessage=function(msg,deferred){if(deferred){var afWorker=this;return void Promise.resolve().then(function(){afWorker.worker.postMessage(msg)})}this.worker.postMessage(msg)},AutoFetcher.prototype.preserveSrcset=function(srcset,mod){this.postMessage({type:"values",srcset:{value:srcset,mod:mod,presplit:true}},true)},AutoFetcher.prototype.preserveDataSrcset=function(elem){this.postMessage({type:"values",srcset:{value:elem.dataset.srcset,mod:this.rwMod(elem),presplit:false}},true)},AutoFetcher.prototype.preserveMedia=function(media){this.postMessage({type:"values",media:media},true)},AutoFetcher.prototype.getSrcset=function(elem){return this.wombat.wb_getAttribute?this.wombat.wb_getAttribute.call(elem,"srcset"):elem.getAttribute("srcset")},AutoFetcher.prototype.rwMod=function(elem){switch(elem.tagName){case"SOURCE":return elem.parentElement&&elem.parentElement.tagName==="PICTURE"?"im_":"oe_";case"IMG":return"im_";}return"oe_"},AutoFetcher.prototype.extractFromLocalDoc=function(){var afw=this;Promise.resolve().then(function(){for(var msg={type:"values",context:{docBaseURI:document.baseURI}},media=[],i=0,sheets=document.styleSheets;i=0)||scriptType.indexOf("text/template")>=0)},Wombat.prototype.skipWrapScriptTextBasedOnText=function(text){if(!text||text.indexOf(this.WB_ASSIGN_FUNC)>=0||text.indexOf("<")===0)return true;for(var override_props=["window","self","document","location","top","parent","frames","opener"],i=0;i=0)return false;return true},Wombat.prototype.nodeHasChildren=function(node){if(!node)return false;if(typeof node.hasChildNodes==="function")return node.hasChildNodes();var kids=node.children||node.childNodes;return!!kids&&kids.length>0},Wombat.prototype.rwModForElement=function(elem,attrName){if(!elem)return undefined;var mod="mp_";if(!(elem.tagName==="LINK"&&attrName==="href")){var maybeMod=this.tagToMod[elem.tagName];maybeMod!=null&&(mod=maybeMod[attrName])}else if(elem.rel){var relV=elem.rel.trim().toLowerCase(),asV=this.wb_getAttribute.call(elem,"as");if(asV&&this.linkTagMods.linkRelToAs[relV]!=null){var asMods=this.linkTagMods.linkRelToAs[relV];mod=asMods[asV.toLowerCase()]}else this.linkTagMods[relV]!=null&&(mod=this.linkTagMods[relV])}return mod},Wombat.prototype.removeWBOSRC=function(elem){elem.tagName!=="SCRIPT"||elem.__$removedWBOSRC$__||(elem.hasAttribute("__wb_orig_src")&&elem.removeAttribute("__wb_orig_src"),elem.__$removedWBOSRC$__=true)},Wombat.prototype.retrieveWBOSRC=function(elem){if(elem.tagName==="SCRIPT"&&!elem.__$removedWBOSRC$__){var maybeWBOSRC;return maybeWBOSRC=this.wb_getAttribute?this.wb_getAttribute.call(elem,"__wb_orig_src"):elem.getAttribute("__wb_orig_src"),maybeWBOSRC==null&&(elem.__$removedWBOSRC$__=true),maybeWBOSRC}return undefined},Wombat.prototype.wrapScriptTextJsProxy=function(scriptText){return"var _____WB$wombat$assign$function_____ = function(name) {return (self._wb_wombat && self._wb_wombat.local_init && self._wb_wombat.local_init(name)) || self[name]; };\nif (!self.__WB_pmw) { self.__WB_pmw = function(obj) { this.__WB_source = obj; return this; } }\n{\nlet window = _____WB$wombat$assign$function_____(\"window\");\nlet self = _____WB$wombat$assign$function_____(\"self\");\nlet document = _____WB$wombat$assign$function_____(\"document\");\nlet location = _____WB$wombat$assign$function_____(\"location\");\nlet top = _____WB$wombat$assign$function_____(\"top\");\nlet parent = _____WB$wombat$assign$function_____(\"parent\");\nlet frames = _____WB$wombat$assign$function_____(\"frames\");\nlet opener = _____WB$wombat$assign$function_____(\"opener\");\n"+scriptText.replace(this.DotPostMessageRe,".__WB_pmw(self.window)$1")+"\n\n}"},Wombat.prototype.watchElem=function(elem,func){if(!this.$wbwindow.MutationObserver)return false;var m=new this.$wbwindow.MutationObserver(function(records,observer){for(var r,i=0;i"},Wombat.prototype.getFinalUrl=function(useRel,mod,url){var prefix=useRel?this.wb_rel_prefix:this.wb_abs_prefix;return mod==null&&(mod=this.wb_info.mod),this.wb_info.is_live||(prefix+=this.wb_info.wombat_ts),prefix+=mod,prefix[prefix.length-1]!=="/"&&(prefix+="/"),prefix+url},Wombat.prototype.resolveRelUrl=function(url,doc){var docObj=doc||this.$wbwindow.document,parser=this.makeParser(docObj.baseURI,docObj),hash=parser.href.lastIndexOf("#"),href=hash>=0?parser.href.substring(0,hash):parser.href,lastslash=href.lastIndexOf("/");return parser.href=lastslash>=0&&lastslash!==href.length-1?href.substring(0,lastslash+1)+url:href+url,parser.href},Wombat.prototype.extractOriginalURL=function(rewrittenUrl){if(!rewrittenUrl)return"";if(this.wb_is_proxy)return rewrittenUrl;var rwURLString=rewrittenUrl.toString(),url=rwURLString;if(this.startsWithOneOf(url,this.IGNORE_PREFIXES))return url;var start;start=this.startsWith(url,this.wb_abs_prefix)?this.wb_abs_prefix.length:this.wb_rel_prefix&&this.startsWith(url,this.wb_rel_prefix)?this.wb_rel_prefix.length:this.wb_rel_prefix?1:0;var index=url.indexOf("/http",start);return index<0&&(index=url.indexOf("///",start)),index<0&&(index=url.indexOf("/blob:",start)),index<0&&(index=url.indexOf("/about:blank",start)),index>=0?url=url.substr(index+1):(index=url.indexOf(this.wb_replay_prefix),index>=0&&(url=url.substr(index+this.wb_replay_prefix.length)),url.length>4&&url.charAt(2)==="_"&&url.charAt(3)==="/"&&(url=url.substr(4)),url!==rwURLString&&!this.startsWithOneOf(url,this.VALID_PREFIXES)&&!this.startsWith(url,"blob:")&&(url=this.wb_orig_scheme+url)),rwURLString.charAt(0)==="/"&&rwURLString.charAt(1)!=="/"&&this.startsWith(url,this.wb_orig_origin)&&(url=url.substr(this.wb_orig_origin.length)),this.startsWith(url,this.REL_PREFIX)?this.wb_info.wombat_scheme+":"+url:url},Wombat.prototype.makeParser=function(maybeRewrittenURL,doc){var originalURL=this.extractOriginalURL(maybeRewrittenURL),docElem=doc;return doc||(this.$wbwindow.location.href==="about:blank"&&this.$wbwindow.opener?docElem=this.$wbwindow.opener.document:docElem=this.$wbwindow.document),this._makeURLParser(originalURL,docElem)},Wombat.prototype._makeURLParser=function(url,docElem){try{return new this.$wbwindow.URL(url,docElem.baseURI)}catch(e){}var p=docElem.createElement("a");return p._no_rewrite=true,p.href=url,p},Wombat.prototype.defProp=function(obj,prop,setFunc,getFunc,enumerable){var existingDescriptor=Object.getOwnPropertyDescriptor(obj,prop);if(existingDescriptor&&!existingDescriptor.configurable)return false;if(!getFunc)return false;var descriptor={configurable:true,enumerable:enumerable||false,get:getFunc};setFunc&&(descriptor.set=setFunc);try{return Object.defineProperty(obj,prop,descriptor),true}catch(e){return console.warn("Failed to redefine property %s",prop,e.message),false}},Wombat.prototype.defGetterProp=function(obj,prop,getFunc,enumerable){var existingDescriptor=Object.getOwnPropertyDescriptor(obj,prop);if(existingDescriptor&&!existingDescriptor.configurable)return false;if(!getFunc)return false;try{return Object.defineProperty(obj,prop,{configurable:true,enumerable:enumerable||false,get:getFunc}),true}catch(e){return console.warn("Failed to redefine property %s",prop,e.message),false}},Wombat.prototype.getOrigGetter=function(obj,prop){var orig_getter;if(obj.__lookupGetter__&&(orig_getter=obj.__lookupGetter__(prop)),!orig_getter&&Object.getOwnPropertyDescriptor){var props=Object.getOwnPropertyDescriptor(obj,prop);props&&(orig_getter=props.get)}return orig_getter},Wombat.prototype.getOrigSetter=function(obj,prop){var orig_setter;if(obj.__lookupSetter__&&(orig_setter=obj.__lookupSetter__(prop)),!orig_setter&&Object.getOwnPropertyDescriptor){var props=Object.getOwnPropertyDescriptor(obj,prop);props&&(orig_setter=props.set)}return orig_setter},Wombat.prototype.getAllOwnProps=function(obj){for(var ownProps=[],props=Object.getOwnPropertyNames(obj),i=0;i "+final_href),actualLocation.href=final_href}}},Wombat.prototype.checkLocationChange=function(wombatLoc,isTop){var locType=typeof wombatLoc,actual_location=isTop?this.$wbwindow.__WB_replay_top.location:this.$wbwindow.location;locType==="string"?this.updateLocation(wombatLoc,actual_location.href,actual_location):locType==="object"&&this.updateLocation(wombatLoc.href,wombatLoc._orig_href,actual_location)},Wombat.prototype.checkAllLocations=function(){return!this.wb_wombat_updating&&void(this.wb_wombat_updating=true,this.checkLocationChange(this.$wbwindow.WB_wombat_location,false),this.$wbwindow.WB_wombat_location!=this.$wbwindow.__WB_replay_top.WB_wombat_location&&this.checkLocationChange(this.$wbwindow.__WB_replay_top.WB_wombat_location,true),this.wb_wombat_updating=false)},Wombat.prototype.proxyToObj=function(source){if(source)try{var proxyRealObj=source.__WBProxyRealObj__;if(proxyRealObj)return proxyRealObj}catch(e){}return source},Wombat.prototype.objToProxy=function(obj){if(obj)try{var maybeWbProxy=obj._WB_wombat_obj_proxy;if(maybeWbProxy)return maybeWbProxy}catch(e){}return obj},Wombat.prototype.defaultProxyGet=function(obj,prop,ownProps,fnCache){switch(prop){case"__WBProxyRealObj__":return obj;case"location":case"WB_wombat_location":return obj.WB_wombat_location;case"_WB_wombat_obj_proxy":return obj._WB_wombat_obj_proxy;case"__WB_pmw":case"WB_wombat_eval":case this.WB_ASSIGN_FUNC:case this.WB_CHECK_THIS_FUNC:return obj[prop];case"origin":return obj.WB_wombat_location.origin;case"constructor":return obj.constructor;}var retVal=obj[prop],type=typeof retVal;if(type==="function"&&ownProps.indexOf(prop)!==-1){switch(prop){case"requestAnimationFrame":case"cancelAnimationFrame":{if(!this.isNativeFunction(retVal))return retVal;break}}var cachedFN=fnCache[prop];return cachedFN&&cachedFN.original===retVal||(cachedFN={original:retVal,boundFn:retVal.bind(obj)},fnCache[prop]=cachedFN),cachedFN.boundFn}return type==="object"&&retVal&&retVal._WB_wombat_obj_proxy?(retVal instanceof Window&&this.initNewWindowWombat(retVal),retVal._WB_wombat_obj_proxy):retVal},Wombat.prototype.setLoc=function(loc,originalURL){var parser=this.makeParser(originalURL,loc.ownerDocument);loc._orig_href=originalURL,loc._parser=parser;var href=parser.href;loc._hash=parser.hash,loc._href=href,loc._host=parser.host,loc._hostname=parser.hostname,loc._origin=parser.origin?parser.host?parser.origin:"null":parser.protocol+"//"+parser.hostname+(parser.port?":"+parser.port:""),loc._pathname=parser.pathname,loc._port=parser.port,loc._protocol=parser.protocol,loc._search=parser.search,Object.defineProperty||(loc.href=href,loc.hash=parser.hash,loc.host=loc._host,loc.hostname=loc._hostname,loc.origin=loc._origin,loc.pathname=loc._pathname,loc.port=loc._port,loc.protocol=loc._protocol,loc.search=loc._search)},Wombat.prototype.makeGetLocProp=function(prop,origGetter){var wombat=this;return function newGetLocProp(){if(this._no_rewrite)return origGetter.call(this,prop);var curr_orig_href=origGetter.call(this,"href");return prop==="href"?wombat.extractOriginalURL(curr_orig_href):prop==="ancestorOrigins"?[]:(this._orig_href!==curr_orig_href&&wombat.setLoc(this,curr_orig_href),this["_"+prop])}},Wombat.prototype.makeSetLocProp=function(prop,origSetter,origGetter){var wombat=this;return function newSetLocProp(value){if(this._no_rewrite)return origSetter.call(this,prop,value);if(this["_"+prop]!==value){if(this["_"+prop]=value,!this._parser){var href=origGetter.call(this);this._parser=wombat.makeParser(href,this.ownerDocument)}var rel=false;prop==="href"&&typeof value==="string"&&value&&(value[0]==="."||value[0]==="#"?value=wombat.resolveRelUrl(value,this.ownerDocument):value[0]==="/"&&(value.length<=1||value[1]!=="/")&&(rel=true,value=WB_wombat_location.origin+value));try{this._parser[prop]=value}catch(e){console.log("Error setting "+prop+" = "+value)}prop==="hash"?(value=this._parser[prop],origSetter.call(this,"hash",value)):(rel=rel||value===this._parser.pathname,value=wombat.rewriteUrl(this._parser.href,rel),origSetter.call(this,"href",value))}}},Wombat.prototype.styleReplacer=function(match,n1,n2,n3,offset,string){return n1+this.rewriteUrl(n2)+n3},Wombat.prototype.domConstructorErrorChecker=function(thisObj,what,args,numRequiredArgs){var errorMsg,needArgs=typeof numRequiredArgs==="number"?numRequiredArgs:1;if(thisObj instanceof Window?errorMsg="Failed to construct '"+what+"': Please use the 'new' operator, this DOM object constructor cannot be called as a function.":args&&args.length=0)return url;if(url.indexOf(this.wb_rel_prefix)===0&&url.indexOf("http")>1){var scheme_sep=url.indexOf(":/");return scheme_sep>0&&url[scheme_sep+2]!=="/"?url.substring(0,scheme_sep+2)+"/"+url.substring(scheme_sep+2):url}return this.getFinalUrl(true,mod,this.wb_orig_origin+url)}url.charAt(0)==="."&&(url=this.resolveRelUrl(url,doc));var prefix=this.startsWithOneOf(url.toLowerCase(),this.VALID_PREFIXES);if(prefix){var orig_host=this.$wbwindow.__WB_replay_top.location.host,orig_protocol=this.$wbwindow.__WB_replay_top.location.protocol,prefix_host=prefix+orig_host+"/";if(this.startsWith(url,prefix_host)){if(this.startsWith(url,this.wb_replay_prefix))return url;var curr_scheme=orig_protocol+"//",path=url.substring(prefix_host.length),rebuild=false;return path.indexOf(this.wb_rel_prefix)<0&&url.indexOf("/static/")<0&&(path=this.getFinalUrl(true,mod,WB_wombat_location.origin+"/"+path),rebuild=true),prefix!==curr_scheme&&prefix!==this.REL_PREFIX&&(rebuild=true),rebuild&&(url=useRel?"":curr_scheme+orig_host,path&&path[0]!=="/"&&(url+="/"),url+=path),url}return this.getFinalUrl(useRel,mod,url)}return prefix=this.startsWithOneOf(url,this.BAD_PREFIXES),prefix?this.getFinalUrl(useRel,mod,this.extractOriginalURL(url)):url},Wombat.prototype.rewriteUrl=function(url,useRel,mod,doc){var rewritten=this.rewriteUrl_(url,useRel,mod,doc);return this.debug_rw&&(url===rewritten?console.log("NOT REWRITTEN "+url):console.log("REWRITE: "+url+" -> "+rewritten)),rewritten},Wombat.prototype.performAttributeRewrite=function(elem,name,value,absUrlOnly){switch(name){case"innerHTML":case"outerHTML":return this.rewriteHtml(value);case"filter":return this.rewriteInlineStyle(value);case"style":return this.rewriteStyle(value);case"srcset":return this.rewriteSrcset(value,elem);}if(absUrlOnly&&!this.startsWithOneOf(value,this.VALID_PREFIXES))return value;var mod=this.rwModForElement(elem,name);return this.wbUseAFWorker&&this.WBAutoFetchWorker&&this.isSavedDataSrcSrcset(elem)&&this.WBAutoFetchWorker.preserveDataSrcset(elem),this.rewriteUrl(value,false,mod,elem.ownerDocument)},Wombat.prototype.rewriteAttr=function(elem,name,absUrlOnly){var changed=false;if(!elem||!elem.getAttribute||elem._no_rewrite||elem["_"+name])return changed;var value=this.wb_getAttribute.call(elem,name);if(!value||this.startsWith(value,"javascript:"))return changed;var new_value=this.performAttributeRewrite(elem,name,value,absUrlOnly);return new_value!==value&&(this.removeWBOSRC(elem),this.wb_setAttribute.call(elem,name,new_value),changed=true),changed},Wombat.prototype.noExceptRewriteStyle=function(style){try{return this.rewriteStyle(style)}catch(e){return style}},Wombat.prototype.rewriteStyle=function(style){if(!style)return style;var value=style;return typeof style==="object"&&(value=style.toString()),typeof value==="string"?value.replace(this.STYLE_REGEX,this.styleReplacer).replace(this.IMPORT_REGEX,this.styleReplacer).replace(this.no_wombatRe,""):value},Wombat.prototype.rewriteSrcset=function(value,elem){if(!value)return"";for(var split=value.split(this.srcsetRe),values=[],mod=this.rwModForElement(elem,"srcset"),i=0;i=0){var JS="javascript:";new_value="javascript:window.parent._wb_wombat.initNewWindowWombat(window);"+value.substr(11)}return new_value||(new_value=this.rewriteUrl(value,false,this.rwModForElement(elem,attrName))),new_value!==value&&(this.wb_setAttribute.call(elem,attrName,new_value),true)},Wombat.prototype.rewriteScript=function(elem){if(elem.hasAttribute("src")||!elem.textContent||!this.$wbwindow.Proxy)return this.rewriteAttr(elem,"src");if(this.skipWrapScriptBasedOnType(elem.type))return false;var text=elem.textContent.trim();return!this.skipWrapScriptTextBasedOnText(text)&&(elem.textContent=this.wrapScriptTextJsProxy(text),true)},Wombat.prototype.rewriteSVGElem=function(elem){var changed=this.rewriteAttr(elem,"filter");return changed=this.rewriteAttr(elem,"style")||changed,changed=this.rewriteAttr(elem,"xlink:href")||changed,changed=this.rewriteAttr(elem,"href")||changed,changed=this.rewriteAttr(elem,"src")||changed,changed},Wombat.prototype.rewriteElem=function(elem){var changed=false;if(!elem)return changed;if(elem instanceof SVGElement)changed=this.rewriteSVGElem(elem);else switch(elem.tagName){case"META":var maybeCSP=this.wb_getAttribute.call(elem,"http-equiv");maybeCSP&&maybeCSP.toLowerCase()==="content-security-policy"&&(this.wb_setAttribute.call(elem,"http-equiv","_"+maybeCSP),changed=true);break;case"STYLE":var new_content=this.rewriteStyle(elem.textContent);elem.textContent!==new_content&&(elem.textContent=new_content,changed=true,this.wbUseAFWorker&&this.WBAutoFetchWorker&&elem.sheet!=null&&this.WBAutoFetchWorker.deferredSheetExtraction(elem.sheet));break;case"LINK":changed=this.rewriteAttr(elem,"href"),this.wbUseAFWorker&&elem.rel==="stylesheet"&&this._addEventListener(elem,"load",this.utilFns.wbSheetMediaQChecker);break;case"IMG":changed=this.rewriteAttr(elem,"src"),changed=this.rewriteAttr(elem,"srcset")||changed,changed=this.rewriteAttr(elem,"style")||changed,this.wbUseAFWorker&&this.WBAutoFetchWorker&&elem.dataset.srcset&&this.WBAutoFetchWorker.preserveDataSrcset(elem);break;case"OBJECT":if(this.wb_info.isSW&&elem.parentElement&&elem.getAttribute("type")==="application/pdf"){for(var iframe=this.$wbwindow.document.createElement("IFRAME"),i=0;i0;)for(var child,children=rewriteQ.shift(),i=0;i"+rwString+"","text/html");if(!inner_doc||!this.nodeHasChildren(inner_doc.head)||!inner_doc.head.children[0].content)return rwString;var template=inner_doc.head.children[0];if(template._no_rewrite=true,this.recurseRewriteElem(template.content)){var new_html=template.innerHTML;if(checkEndTag){var first_elem=template.content.children&&template.content.children[0];if(first_elem){var end_tag="";this.endsWith(new_html,end_tag)&&!this.endsWith(rwString.toLowerCase(),end_tag)&&(new_html=new_html.substring(0,new_html.length-end_tag.length))}else if(rwString[0]!=="<"||rwString[rwString.length-1]!==">")return this.write_buff+=rwString,undefined}return new_html}return rwString},Wombat.prototype.rewriteHtmlFull=function(string,checkEndTag){var inner_doc=new DOMParser().parseFromString(string,"text/html");if(!inner_doc)return string;for(var changed=false,i=0;i=0)inner_doc.documentElement._no_rewrite=true,new_html=this.reconstructDocType(inner_doc.doctype)+inner_doc.documentElement.outerHTML;else{inner_doc.head._no_rewrite=true,inner_doc.body._no_rewrite=true;var headHasKids=this.nodeHasChildren(inner_doc.head),bodyHasKids=this.nodeHasChildren(inner_doc.body);if(new_html=(headHasKids?inner_doc.head.outerHTML:"")+(bodyHasKids?inner_doc.body.outerHTML:""),checkEndTag)if(inner_doc.all.length>3){var end_tag="";this.endsWith(new_html,end_tag)&&!this.endsWith(string.toLowerCase(),end_tag)&&(new_html=new_html.substring(0,new_html.length-end_tag.length))}else if(string[0]!=="<"||string[string.length-1]!==">")return void(this.write_buff+=string);new_html=this.reconstructDocType(inner_doc.doctype)+new_html}return new_html}return string},Wombat.prototype.rewriteInlineStyle=function(orig){var decoded;try{decoded=decodeURIComponent(orig)}catch(e){decoded=orig}if(decoded!==orig){var parts=this.rewriteStyle(decoded).split(",",2);return parts[0]+","+encodeURIComponent(parts[1])}return this.rewriteStyle(orig)},Wombat.prototype.rewriteCookie=function(cookie){var wombat=this,rwCookie=cookie.replace(this.wb_abs_prefix,"").replace(this.wb_rel_prefix,"");return rwCookie=rwCookie.replace(this.cookie_domain_regex,function(m,m1){var message={domain:m1,cookie:rwCookie,wb_type:"cookie"};return wombat.sendTopMessage(message,true),wombat.$wbwindow.location.hostname.indexOf(".")>=0&&!wombat.IP_RX.test(wombat.$wbwindow.location.hostname)?"Domain=."+wombat.$wbwindow.location.hostname:""}).replace(this.cookie_path_regex,function(m,m1){var rewritten=wombat.rewriteUrl(m1);return rewritten.indexOf(wombat.wb_curr_host)===0&&(rewritten=rewritten.substring(wombat.wb_curr_host.length)),"Path="+rewritten}),wombat.$wbwindow.location.protocol!=="https:"&&(rwCookie=rwCookie.replace("secure","")),rwCookie.replace(",|",",")},Wombat.prototype.rewriteWorker=function(workerUrl){if(!workerUrl)return workerUrl;workerUrl=workerUrl.toString();var isBlob=workerUrl.indexOf("blob:")===0,isJS=workerUrl.indexOf("javascript:")===0;if(!isBlob&&!isJS){if(!this.startsWithOneOf(workerUrl,this.VALID_PREFIXES)&&!this.startsWith(workerUrl,"/")&&!this.startsWithOneOf(workerUrl,this.BAD_PREFIXES)){var rurl=this.resolveRelUrl(workerUrl,this.$wbwindow.document);return this.rewriteUrl(rurl,false,"wkr_",this.$wbwindow.document)}return this.rewriteUrl(workerUrl,false,"wkr_",this.$wbwindow.document)}var workerCode=isJS?workerUrl.replace("javascript:",""):null;if(isBlob){var x=new XMLHttpRequest;this.utilFns.XHRopen.call(x,"GET",workerUrl,false),this.utilFns.XHRsend.call(x),workerCode=x.responseText.replace(this.workerBlobRe,"").replace(this.rmCheckThisInjectRe,"this")}if(this.wb_info.static_prefix||this.wb_info.ww_rw_script){var originalURL=this.$wbwindow.document.baseURI,ww_rw=this.wb_info.ww_rw_script||this.wb_info.static_prefix+"wombatWorkers.js",rw="(function() { self.importScripts('"+ww_rw+"'); new WBWombat({'prefix': '"+this.wb_abs_prefix+"', 'prefixMod': '"+this.wb_abs_prefix+"wkrf_/', 'originalURL': '"+originalURL+"'}); })();";workerCode=rw+workerCode}var blob=new Blob([workerCode],{type:"application/javascript"});return URL.createObjectURL(blob)},Wombat.prototype.rewriteTextNodeFn=function(fnThis,originalFn,argsObj){var args,deproxiedThis=this.proxyToObj(fnThis);if(argsObj.length>0&&deproxiedThis.parentElement&&deproxiedThis.parentElement.tagName==="STYLE"){args=new Array(argsObj.length);var dataIndex=argsObj.length-1;dataIndex===2?(args[0]=argsObj[0],args[1]=argsObj[1]):dataIndex===1&&(args[0]=argsObj[0]),args[dataIndex]=this.rewriteStyle(argsObj[dataIndex])}else args=argsObj;return originalFn.__WB_orig_apply?originalFn.__WB_orig_apply(deproxiedThis,args):originalFn.apply(deproxiedThis,args)},Wombat.prototype.rewriteDocWriteWriteln=function(fnThis,originalFn,argsObj){var string,thisObj=this.proxyToObj(fnThis),argLen=argsObj.length;if(argLen===0)return originalFn.call(thisObj);string=argLen===1?argsObj[0]:Array.prototype.join.call(argsObj,"");var new_buff=this.rewriteHtml(string,true),res=originalFn.call(thisObj,new_buff);return this.initNewWindowWombat(thisObj.defaultView),res},Wombat.prototype.rewriteChildNodeFn=function(fnThis,originalFn,argsObj){var thisObj=this.proxyToObj(fnThis);if(argsObj.length===0)return originalFn.call(thisObj);var newArgs=this.rewriteElementsInArguments(argsObj);return originalFn.__WB_orig_apply?originalFn.__WB_orig_apply(thisObj,newArgs):originalFn.apply(thisObj,newArgs)},Wombat.prototype.rewriteInsertAdjHTMLOrElemArgs=function(fnThis,originalFn,position,textOrElem,rwHTML){var fnThisObj=this.proxyToObj(fnThis);return fnThisObj._no_rewrite?originalFn.call(fnThisObj,position,textOrElem):rwHTML?originalFn.call(fnThisObj,position,this.rewriteHtml(textOrElem)):(this.rewriteElemComplete(textOrElem),originalFn.call(fnThisObj,position,textOrElem))},Wombat.prototype.rewriteSetTimeoutInterval=function(fnThis,originalFn,argsObj){var rw=this.isString(argsObj[0]),args=rw?new Array(argsObj.length):argsObj;if(rw){args[0]=this.$wbwindow.Proxy?this.wrapScriptTextJsProxy(argsObj[0]):argsObj[0].replace(/\blocation\b/g,"WB_wombat_$&");for(var i=1;i0&&cssStyleValueOverride(this.$wbwindow.CSSStyleValue,"parse"),this.$wbwindow.CSSStyleValue.parseAll&&this.$wbwindow.CSSStyleValue.parseAll.toString().indexOf("[native code]")>0&&cssStyleValueOverride(this.$wbwindow.CSSStyleValue,"parseAll")}if(this.$wbwindow.CSSKeywordValue&&this.$wbwindow.CSSKeywordValue.prototype){var oCSSKV=this.$wbwindow.CSSKeywordValue;this.$wbwindow.CSSKeywordValue=function(CSSKeywordValue_){return function CSSKeywordValue(cssValue){return wombat.domConstructorErrorChecker(this,"CSSKeywordValue",arguments),new CSSKeywordValue_(wombat.rewriteStyle(cssValue))}}(this.$wbwindow.CSSKeywordValue),this.$wbwindow.CSSKeywordValue.prototype=oCSSKV.prototype,Object.defineProperty(this.$wbwindow.CSSKeywordValue.prototype,"constructor",{value:this.$wbwindow.CSSKeywordValue}),addToStringTagToClass(this.$wbwindow.CSSKeywordValue,"CSSKeywordValue")}if(this.$wbwindow.StylePropertyMap&&this.$wbwindow.StylePropertyMap.prototype){var originalSet=this.$wbwindow.StylePropertyMap.prototype.set;this.$wbwindow.StylePropertyMap.prototype.set=function set(){if(arguments.length<=1)return originalSet.__WB_orig_apply?originalSet.__WB_orig_apply(this,arguments):originalSet.apply(this,arguments);var newArgs=new Array(arguments.length);newArgs[0]=arguments[0];for(var i=1;i")&&(array[0]=wombat.rewriteHtml(array[0]),options.type="text/html"),new Blob_(array,options)}}(this.$wbwindow.Blob),this.$wbwindow.Blob.prototype=orig_blob.prototype}},Wombat.prototype.initDocTitleOverride=function(){var orig_get_title=this.getOrigGetter(this.$wbwindow.document,"title"),orig_set_title=this.getOrigSetter(this.$wbwindow.document,"title"),wombat=this,set_title=function title(value){var res=orig_set_title.call(this,value),message={wb_type:"title",title:value};return wombat.sendTopMessage(message),res};this.defProp(this.$wbwindow.document,"title",set_title,orig_get_title)},Wombat.prototype.initFontFaceOverride=function(){if(this.$wbwindow.FontFace){var wombat=this,origFontFace=this.$wbwindow.FontFace;this.$wbwindow.FontFace=function(FontFace_){return function FontFace(family,source,descriptors){wombat.domConstructorErrorChecker(this,"FontFace",arguments,2);var rwSource=source;return source!=null&&(typeof source==="string"?rwSource=wombat.rewriteInlineStyle(source):rwSource=wombat.rewriteInlineStyle(source.toString())),new FontFace_(family,rwSource,descriptors)}}(this.$wbwindow.FontFace),this.$wbwindow.FontFace.prototype=origFontFace.prototype,Object.defineProperty(this.$wbwindow.FontFace.prototype,"constructor",{value:this.$wbwindow.FontFace}),addToStringTagToClass(this.$wbwindow.FontFace,"FontFace")}},Wombat.prototype.initFixedRatio=function(val){try{this.$wbwindow.devicePixelRatio=val}catch(e){}if(Object.defineProperty)try{Object.defineProperty(this.$wbwindow,"devicePixelRatio",{value:value,writable:false})}catch(e){}},Wombat.prototype.initPaths=function(wbinfo){wbinfo.wombat_opts=wbinfo.wombat_opts||{},Object.assign(this.wb_info,wbinfo),this.wb_opts=wbinfo.wombat_opts,this.wb_replay_prefix=wbinfo.prefix,this.wb_is_proxy=wbinfo.proxy_magic||!this.wb_replay_prefix,this.wb_info.top_host=this.wb_info.top_host||"*",this.wb_curr_host=this.$wbwindow.location.protocol+"//"+this.$wbwindow.location.host,this.wb_info.wombat_opts=this.wb_info.wombat_opts||{},this.wb_orig_scheme=wbinfo.wombat_scheme+"://",this.wb_orig_origin=this.wb_orig_scheme+wbinfo.wombat_host,this.wb_abs_prefix=this.wb_replay_prefix,this.wb_capture_date_part=!wbinfo.is_live&&wbinfo.wombat_ts?"/"+wbinfo.wombat_ts+"/":"",this.initBadPrefixes(this.wb_replay_prefix),this.initCookiePreset()},Wombat.prototype.initSeededRandom=function(seed){this.$wbwindow.Math.seed=parseInt(seed);var wombat=this;this.$wbwindow.Math.random=function random(){return wombat.$wbwindow.Math.seed=(wombat.$wbwindow.Math.seed*9301+49297)%233280,wombat.$wbwindow.Math.seed/233280}},Wombat.prototype.initHistoryOverrides=function(){this.overrideHistoryFunc("pushState"),this.overrideHistoryFunc("replaceState");var wombat=this;this.$wbwindow.addEventListener("popstate",function(event){wombat.sendHistoryUpdate(wombat.$wbwindow.WB_wombat_location.href,wombat.$wbwindow.document.title)})},Wombat.prototype.initCookiePreset=function(){if(this.wb_info.presetCookie)for(var splitCookies=this.wb_info.presetCookie.split(";"),i=0;i0?"&":"?")+"__wb_method="+this.__WB_xhr_open_arguments[0]+"&"+newValue,this.__WB_xhr_open_arguments[0]="GET",value=null}if(this.__WB_xhr_open_arguments.length>2&&(this.__WB_xhr_open_arguments[2]=true),this._no_rewrite||(this.__WB_xhr_open_arguments[1]=wombat.rewriteUrl(this.__WB_xhr_open_arguments[1])),origOpen.apply(this,this.__WB_xhr_open_arguments),!wombat.startsWith(this.__WB_xhr_open_arguments[1],"data:")){for(const[name,value]of this.__WB_xhr_headers.entries())origSetRequestHeader.call(this,name,value);origSetRequestHeader.call(this,"X-Pywb-Requested-With","XMLHttpRequest")}origSend.call(this,value)}}if(this.$wbwindow.fetch){var orig_fetch=this.$wbwindow.fetch;this.$wbwindow.fetch=function fetch(input,init_opts){var rwInput=input,inputType=typeof input;if(inputType==="string")rwInput=wombat.rewriteUrl(input);else if(inputType==="object"&&input.url){var new_url=wombat.rewriteUrl(input.url);new_url!==input.url&&(rwInput=new Request(new_url,init_opts))}else inputType==="object"&&input.href&&(rwInput=wombat.rewriteUrl(input.href));if(init_opts||(init_opts={}),init_opts.credentials===undefined)try{init_opts.credentials="include"}catch(e){}return orig_fetch.call(wombat.proxyToObj(this),rwInput,init_opts)}}if(this.$wbwindow.Request&&this.$wbwindow.Request.prototype){var orig_request=this.$wbwindow.Request;this.$wbwindow.Request=function(Request_){return function Request(input,init_opts){wombat.domConstructorErrorChecker(this,"Request",arguments);var newInitOpts=init_opts||{},newInput=input,inputType=typeof input;switch(inputType){case"string":newInput=wombat.rewriteUrl(input);break;case"object":if(newInput=input,input.url){var new_url=wombat.rewriteUrl(input.url);new_url!==input.url&&(newInput=new Request_(new_url,input))}else input.href&&(newInput=wombat.rewriteUrl(input.toString(),true));}return newInitOpts.credentials="include",new Request_(newInput,newInitOpts)}}(this.$wbwindow.Request),this.$wbwindow.Request.prototype=orig_request.prototype,Object.defineProperty(this.$wbwindow.Request.prototype,"constructor",{value:this.$wbwindow.Request})}if(this.$wbwindow.Response&&this.$wbwindow.Response.prototype){var originalRedirect=this.$wbwindow.Response.prototype.redirect;this.$wbwindow.Response.prototype.redirect=function redirect(url,status){var rwURL=wombat.rewriteUrl(url,true,null,wombat.$wbwindow.document);return originalRedirect.call(this,rwURL,status)}}if(this.$wbwindow.EventSource&&this.$wbwindow.EventSource.prototype){var origEventSource=this.$wbwindow.EventSource;this.$wbwindow.EventSource=function(EventSource_){return function EventSource(url,configuration){wombat.domConstructorErrorChecker(this,"EventSource",arguments);var rwURL=url;return url!=null&&(rwURL=wombat.rewriteUrl(url)),new EventSource_(rwURL,configuration)}}(this.$wbwindow.EventSource),this.$wbwindow.EventSource.prototype=origEventSource.prototype,Object.defineProperty(this.$wbwindow.EventSource.prototype,"constructor",{value:this.$wbwindow.EventSource}),addToStringTagToClass(this.$wbwindow.EventSource,"EventSource")}if(this.$wbwindow.WebSocket&&this.$wbwindow.WebSocket.prototype){var origWebSocket=this.$wbwindow.WebSocket;this.$wbwindow.WebSocket=function(WebSocket_){return function WebSocket(url,configuration){wombat.domConstructorErrorChecker(this,"WebSocket",arguments);var rwURL=url;return url!=null&&(rwURL=wombat.rewriteWSURL(url)),new WebSocket_(rwURL,configuration)}}(this.$wbwindow.WebSocket),this.$wbwindow.WebSocket.prototype=origWebSocket.prototype,Object.defineProperty(this.$wbwindow.WebSocket.prototype,"constructor",{value:this.$wbwindow.WebSocket}),addToStringTagToClass(this.$wbwindow.WebSocket,"WebSocket")}},Wombat.prototype.initElementGetSetAttributeOverride=function(){if(!this.wb_opts.skip_setAttribute&&this.$wbwindow.Element&&this.$wbwindow.Element.prototype){var wombat=this,ElementProto=this.$wbwindow.Element.prototype;if(ElementProto.setAttribute){var orig_setAttribute=ElementProto.setAttribute;ElementProto._orig_setAttribute=orig_setAttribute,ElementProto.setAttribute=function setAttribute(name,value){var rwValue=value;if(name&&typeof rwValue==="string"){var lowername=name.toLowerCase();if(this.tagName==="LINK"&&lowername==="href"&&rwValue.indexOf("data:text/css")===0)rwValue=wombat.rewriteInlineStyle(value);else if(lowername==="style")rwValue=wombat.rewriteStyle(value);else if(lowername==="srcset")rwValue=wombat.rewriteSrcset(value,this);else{var shouldRW=wombat.shouldRewriteAttr(this.tagName,lowername);shouldRW&&(wombat.removeWBOSRC(this),!this._no_rewrite&&(rwValue=wombat.rewriteUrl(value,false,wombat.rwModForElement(this,lowername))))}}return orig_setAttribute.call(this,name,rwValue)}}if(ElementProto.getAttribute){var orig_getAttribute=ElementProto.getAttribute;this.wb_getAttribute=orig_getAttribute,ElementProto.getAttribute=function getAttribute(name){var result=orig_getAttribute.call(this,name);if(result===null)return result;var lowerName=name;if(name&&(lowerName=name.toLowerCase()),wombat.shouldRewriteAttr(this.tagName,lowerName)){var maybeWBOSRC=wombat.retrieveWBOSRC(this);return maybeWBOSRC?maybeWBOSRC:wombat.extractOriginalURL(result)}return wombat.startsWith(lowerName,"data-")&&wombat.startsWithOneOf(result,wombat.wb_prefixes)?wombat.extractOriginalURL(result):result}}}},Wombat.prototype.initSvgImageOverrides=function(){if(this.$wbwindow.SVGImageElement){var svgImgProto=this.$wbwindow.SVGImageElement.prototype,orig_getAttr=svgImgProto.getAttribute,orig_getAttrNS=svgImgProto.getAttributeNS,orig_setAttr=svgImgProto.setAttribute,orig_setAttrNS=svgImgProto.setAttributeNS,wombat=this;svgImgProto.getAttribute=function getAttribute(name){var value=orig_getAttr.call(this,name);return name.indexOf("xlink:href")>=0||name==="href"?wombat.extractOriginalURL(value):value},svgImgProto.getAttributeNS=function getAttributeNS(ns,name){var value=orig_getAttrNS.call(this,ns,name);return name.indexOf("xlink:href")>=0||name==="href"?wombat.extractOriginalURL(value):value},svgImgProto.setAttribute=function setAttribute(name,value){var rwValue=value;return(name.indexOf("xlink:href")>=0||name==="href")&&(rwValue=wombat.rewriteUrl(value)),orig_setAttr.call(this,name,rwValue)},svgImgProto.setAttributeNS=function setAttributeNS(ns,name,value){var rwValue=value;return(name.indexOf("xlink:href")>=0||name==="href")&&(rwValue=wombat.rewriteUrl(value)),orig_setAttrNS.call(this,ns,name,rwValue)}}},Wombat.prototype.initCreateElementNSFix=function(){if(this.$wbwindow.document.createElementNS&&this.$wbwindow.Document.prototype.createElementNS){var orig_createElementNS=this.$wbwindow.document.createElementNS,wombat=this,createElementNS=function createElementNS(namespaceURI,qualifiedName){return orig_createElementNS.call(wombat.proxyToObj(this),wombat.extractOriginalURL(namespaceURI),qualifiedName)};this.$wbwindow.Document.prototype.createElementNS=createElementNS,this.$wbwindow.document.createElementNS=createElementNS}},Wombat.prototype.initInsertAdjacentElementHTMLOverrides=function(){var Element=this.$wbwindow.Element;if(Element&&Element.prototype){var elementProto=Element.prototype,rewriteFn=this.rewriteInsertAdjHTMLOrElemArgs;if(elementProto.insertAdjacentHTML){var origInsertAdjacentHTML=elementProto.insertAdjacentHTML;elementProto.insertAdjacentHTML=function insertAdjacentHTML(position,text){return rewriteFn(this,origInsertAdjacentHTML,position,text,true)}}if(elementProto.insertAdjacentElement){var origIAdjElem=elementProto.insertAdjacentElement;elementProto.insertAdjacentElement=function insertAdjacentElement(position,element){return rewriteFn(this,origIAdjElem,position,element,false)}}}},Wombat.prototype.initDomOverride=function(){var Node=this.$wbwindow.Node;if(Node&&Node.prototype){var rewriteFn=this.rewriteNodeFuncArgs;if(Node.prototype.appendChild){var originalAppendChild=Node.prototype.appendChild;Node.prototype.appendChild=function appendChild(newNode,oldNode){return rewriteFn(this,originalAppendChild,newNode,oldNode)}}if(Node.prototype.insertBefore){var originalInsertBefore=Node.prototype.insertBefore;Node.prototype.insertBefore=function insertBefore(newNode,oldNode){return rewriteFn(this,originalInsertBefore,newNode,oldNode)}}if(Node.prototype.replaceChild){var originalReplaceChild=Node.prototype.replaceChild;Node.prototype.replaceChild=function replaceChild(newNode,oldNode){return rewriteFn(this,originalReplaceChild,newNode,oldNode)}}this.overridePropToProxy(Node.prototype,"ownerDocument"),this.overridePropToProxy(this.$wbwindow.HTMLHtmlElement.prototype,"parentNode"),this.overridePropToProxy(this.$wbwindow.Event.prototype,"target")}this.$wbwindow.Element&&this.$wbwindow.Element.prototype&&(this.overrideParentNodeAppendPrepend(this.$wbwindow.Element),this.overrideChildNodeInterface(this.$wbwindow.Element,false)),this.$wbwindow.DocumentFragment&&this.$wbwindow.DocumentFragment.prototype&&this.overrideParentNodeAppendPrepend(this.$wbwindow.DocumentFragment)},Wombat.prototype.initDocOverrides=function($document){if(Object.defineProperty){this.overrideReferrer($document),this.defGetterProp($document,"origin",function origin(){return this.WB_wombat_location.origin}),this.defGetterProp(this.$wbwindow,"origin",function origin(){return this.WB_wombat_location.origin});var wombat=this,domain_setter=function domain(val){var loc=this.WB_wombat_location;loc&&wombat.endsWith(loc.hostname,val)&&(this.__wb_domain=val)},domain_getter=function domain(){return this.__wb_domain||this.WB_wombat_location.hostname};this.defProp($document,"domain",domain_setter,domain_getter)}},Wombat.prototype.initDocWriteOpenCloseOverride=function(){if(this.$wbwindow.DOMParser){var DocumentProto=this.$wbwindow.Document.prototype,$wbDocument=this.$wbwindow.document,docWriteWritelnRWFn=this.rewriteDocWriteWriteln,orig_doc_write=$wbDocument.write,new_write=function write(){return docWriteWritelnRWFn(this,orig_doc_write,arguments)};$wbDocument.write=new_write,DocumentProto.write=new_write;var orig_doc_writeln=$wbDocument.writeln,new_writeln=function writeln(){return docWriteWritelnRWFn(this,orig_doc_writeln,arguments)};$wbDocument.writeln=new_writeln,DocumentProto.writeln=new_writeln;var wombat=this,orig_doc_open=$wbDocument.open,new_open=function open(){var res,thisObj=wombat.proxyToObj(this);if(arguments.length===3){var rwUrl=wombat.rewriteUrl(arguments[0],false,"mp_");res=orig_doc_open.call(thisObj,rwUrl,arguments[1],arguments[2]),wombat.initNewWindowWombat(res,arguments[0])}else res=orig_doc_open.call(thisObj),wombat.initNewWindowWombat(thisObj.defaultView);return res};$wbDocument.open=new_open,DocumentProto.open=new_open;var originalClose=$wbDocument.close,newClose=function close(){var thisObj=wombat.proxyToObj(this);return wombat.initNewWindowWombat(thisObj.defaultView),originalClose.__WB_orig_apply?originalClose.__WB_orig_apply(thisObj,arguments):originalClose.apply(thisObj,arguments)};$wbDocument.close=newClose,DocumentProto.close=newClose;var oBodyGetter=this.getOrigGetter(DocumentProto,"body"),oBodySetter=this.getOrigSetter(DocumentProto,"body");oBodyGetter&&oBodySetter&&this.defProp(DocumentProto,"body",function body(newBody){return newBody&&(newBody instanceof HTMLBodyElement||newBody instanceof HTMLFrameSetElement)&&wombat.rewriteElemComplete(newBody),oBodySetter.call(wombat.proxyToObj(this),newBody)},oBodyGetter)}},Wombat.prototype.initIframeWombat=function(iframe){var win;win=iframe._get_contentWindow?iframe._get_contentWindow.call(iframe):iframe.contentWindow;try{if(!win||win===this.$wbwindow||win._skip_wombat||win._wb_wombat)return}catch(e){return}var src=iframe.src;this.initNewWindowWombat(win,src)},Wombat.prototype.initNewWindowWombat=function(win,src){var fullWombat=false;if(win&&!win._wb_wombat){if((!src||src===""||this.startsWithOneOf(src,["about:blank","javascript:"]))&&(fullWombat=true),!fullWombat&&this.wb_info.isSW){var origURL=this.extractOriginalURL(src);(origURL==="about:blank"||origURL.startsWith("srcdoc:")||origURL.startsWith("blob:"))&&(fullWombat=true)}if(fullWombat){var newInfo={};Object.assign(newInfo,this.wb_info);var wombat=new Wombat(win,newInfo);win._wb_wombat=wombat.wombatInit()}else this.initProtoPmOrigin(win),this.initPostMessageOverride(win),this.initMessageEventOverride(win),this.initCheckThisFunc(win)}},Wombat.prototype.initTimeoutIntervalOverrides=function(){var rewriteFn=this.rewriteSetTimeoutInterval;if(this.$wbwindow.setTimeout&&!this.$wbwindow.setTimeout.__$wbpatched$__){var originalSetTimeout=this.$wbwindow.setTimeout;this.$wbwindow.setTimeout=function setTimeout(){return rewriteFn(this,originalSetTimeout,arguments)},this.$wbwindow.setTimeout.__$wbpatched$__=true}if(this.$wbwindow.setInterval&&!this.$wbwindow.setInterval.__$wbpatched$__){var originalSetInterval=this.$wbwindow.setInterval;this.$wbwindow.setInterval=function setInterval(){return rewriteFn(this,originalSetInterval,arguments)},this.$wbwindow.setInterval.__$wbpatched$__=true}},Wombat.prototype.initWorkerOverrides=function(){var wombat=this;if(this.$wbwindow.Worker&&!this.$wbwindow.Worker._wb_worker_overriden){var orig_worker=this.$wbwindow.Worker;this.$wbwindow.Worker=function(Worker_){return function Worker(url,options){return wombat.domConstructorErrorChecker(this,"Worker",arguments),new Worker_(wombat.rewriteWorker(url),options)}}(orig_worker),this.$wbwindow.Worker.prototype=orig_worker.prototype,Object.defineProperty(this.$wbwindow.Worker.prototype,"constructor",{value:this.$wbwindow.Worker}),this.$wbwindow.Worker._wb_worker_overriden=true}if(this.$wbwindow.SharedWorker&&!this.$wbwindow.SharedWorker.__wb_sharedWorker_overriden){var oSharedWorker=this.$wbwindow.SharedWorker;this.$wbwindow.SharedWorker=function(SharedWorker_){return function SharedWorker(url,options){return wombat.domConstructorErrorChecker(this,"SharedWorker",arguments),new SharedWorker_(wombat.rewriteWorker(url),options)}}(oSharedWorker),this.$wbwindow.SharedWorker.prototype=oSharedWorker.prototype,Object.defineProperty(this.$wbwindow.SharedWorker.prototype,"constructor",{value:this.$wbwindow.SharedWorker}),this.$wbwindow.SharedWorker.__wb_sharedWorker_overriden=true}if(this.$wbwindow.ServiceWorkerContainer&&this.$wbwindow.ServiceWorkerContainer.prototype&&this.$wbwindow.ServiceWorkerContainer.prototype.register){var orig_register=this.$wbwindow.ServiceWorkerContainer.prototype.register;this.$wbwindow.ServiceWorkerContainer.prototype.register=function register(scriptURL,options){var newScriptURL=new URL(scriptURL,wombat.$wbwindow.document.baseURI).href,mod=wombat.getPageUnderModifier();return options&&options.scope?options.scope=wombat.rewriteUrl(options.scope,false,mod):options={scope:wombat.rewriteUrl("/",false,mod)},orig_register.call(this,wombat.rewriteUrl(newScriptURL,false,"sw_"),options)}}if(this.$wbwindow.Worklet&&this.$wbwindow.Worklet.prototype&&this.$wbwindow.Worklet.prototype.addModule&&!this.$wbwindow.Worklet.__wb_workerlet_overriden){var oAddModule=this.$wbwindow.Worklet.prototype.addModule;this.$wbwindow.Worklet.prototype.addModule=function addModule(moduleURL,options){var rwModuleURL=wombat.rewriteUrl(moduleURL,false,"js_");return oAddModule.call(this,rwModuleURL,options)},this.$wbwindow.Worklet.__wb_workerlet_overriden=true}},Wombat.prototype.initLocOverride=function(loc,oSetter,oGetter){if(Object.defineProperty)for(var prop,i=0;i=0&&props.splice(foundInx,1);return props}})}catch(e){console.log(e)}},Wombat.prototype.initHashChange=function(){if(this.$wbwindow.__WB_top_frame){var wombat=this,receive_hash_change=function receive_hash_change(event){if(event.data&&event.data.from_top){var message=event.data.message;message.wb_type&&(message.wb_type!=="outer_hashchange"||wombat.$wbwindow.location.hash==message.hash||(wombat.$wbwindow.location.hash=message.hash))}},send_hash_change=function send_hash_change(){var message={wb_type:"hashchange",hash:wombat.$wbwindow.location.hash};wombat.sendTopMessage(message)};this.$wbwindow.addEventListener("message",receive_hash_change),this.$wbwindow.addEventListener("hashchange",send_hash_change)}},Wombat.prototype.initPostMessageOverride=function($wbwindow){if($wbwindow.postMessage&&!$wbwindow.__orig_postMessage){var orig=$wbwindow.postMessage,wombat=this;$wbwindow.__orig_postMessage=orig;var postmessage_rewritten=function postMessage(message,targetOrigin,transfer,from_top){var from,src_id,this_obj=wombat.proxyToObj(this);if(this_obj.__WB_source&&this_obj.__WB_source.WB_wombat_location){var source=this_obj.__WB_source;if(from=source.WB_wombat_location.origin,this_obj.__WB_win_id||(this_obj.__WB_win_id={},this_obj.__WB_counter=0),!source.__WB_id){var id=this_obj.__WB_counter;source.__WB_id=id+source.WB_wombat_location.href,this_obj.__WB_counter+=1}this_obj.__WB_win_id[source.__WB_id]=source,src_id=source.__WB_id,this_obj.__WB_source=undefined}else from=window.WB_wombat_location.origin;var to_origin=targetOrigin;to_origin===this_obj.location.origin&&(to_origin=from);var new_message={from:from,to_origin:to_origin,src_id:src_id,message:message,from_top:from_top};if(targetOrigin!=="*"){if(this_obj.location.origin==="null"||this_obj.location.origin==="")return;targetOrigin=this_obj.location.origin}return orig.call(this_obj,new_message,targetOrigin,transfer)};$wbwindow.postMessage=postmessage_rewritten,$wbwindow.Window.prototype.postMessage=postmessage_rewritten;var eventTarget=null;eventTarget=$wbwindow.EventTarget&&$wbwindow.EventTarget.prototype?$wbwindow.EventTarget.prototype:$wbwindow;var _oAddEventListener=eventTarget.addEventListener;eventTarget.addEventListener=function addEventListener(type,listener,useCapture){var rwListener,obj=wombat.proxyToObj(this);if(type==="message"?rwListener=wombat.message_listeners.add_or_get(listener,function(){return wrapEventListener(listener,obj,wombat)}):type==="storage"?wombat.storage_listeners.add_or_get(listener,function(){return wrapSameOriginEventListener(listener,obj)}):rwListener=listener,rwListener)return _oAddEventListener.call(obj,type,rwListener,useCapture)};var _oRemoveEventListener=eventTarget.removeEventListener;eventTarget.removeEventListener=function removeEventListener(type,listener,useCapture){var rwListener,obj=wombat.proxyToObj(this);if(type==="message"?rwListener=wombat.message_listeners.remove(listener):type==="storage"?wombat.storage_listeners.remove(listener):rwListener=listener,rwListener)return _oRemoveEventListener.call(obj,type,rwListener,useCapture)};var override_on_prop=function(onevent,wrapperFN){var orig_setter=wombat.getOrigSetter($wbwindow,onevent),setter=function(value){this["__orig_"+onevent]=value;var obj=wombat.proxyToObj(this),listener=value?wrapperFN(value,obj,wombat):value;return orig_setter.call(obj,listener)},getter=function(){return this["__orig_"+onevent]};wombat.defProp($wbwindow,onevent,setter,getter)};override_on_prop("onmessage",wrapEventListener),override_on_prop("onstorage",wrapSameOriginEventListener)}},Wombat.prototype.initMessageEventOverride=function($wbwindow){!$wbwindow.MessageEvent||$wbwindow.MessageEvent.prototype.__extended||(this.addEventOverride("target"),this.addEventOverride("srcElement"),this.addEventOverride("currentTarget"),this.addEventOverride("eventPhase"),this.addEventOverride("path"),this.overridePropToProxy($wbwindow.MessageEvent.prototype,"source"),$wbwindow.MessageEvent.prototype.__extended=true)},Wombat.prototype.initUIEventsOverrides=function(){this.overrideAnUIEvent("UIEvent"),this.overrideAnUIEvent("MouseEvent"),this.overrideAnUIEvent("TouchEvent"),this.overrideAnUIEvent("FocusEvent"),this.overrideAnUIEvent("KeyboardEvent"),this.overrideAnUIEvent("WheelEvent"),this.overrideAnUIEvent("InputEvent"),this.overrideAnUIEvent("CompositionEvent")},Wombat.prototype.initOpenOverride=function(){var orig=this.$wbwindow.open;this.$wbwindow.Window.prototype.open&&(orig=this.$wbwindow.Window.prototype.open);var wombat=this,open_rewritten=function open(strUrl,strWindowName,strWindowFeatures){var rwStrUrl=wombat.rewriteUrl(strUrl,false,""),res=orig.call(wombat.proxyToObj(this),rwStrUrl,strWindowName,strWindowFeatures);return wombat.initNewWindowWombat(res,strUrl),res};this.$wbwindow.open=open_rewritten,this.$wbwindow.Window.prototype.open&&(this.$wbwindow.Window.prototype.open=open_rewritten);for(var i=0;i U+0020) EXACT_SUFFIX_SEARCH_B = b'####' # type: bytes - def __init__(self, access_source, default_access='allow'): + def __init__(self, access_source, default_access='allow', embargo=None): """Initialize a new AccessChecker :param str|list[str]|AccessRulesAggregator access_source: An access source :param str default_access: The default access action (allow) + :param dict embargo: A dict specifying optional embargo setting """ if isinstance(access_source, str): self.aggregator = self.create_access_aggregator([access_source]) @@ -103,6 +107,72 @@ def __init__(self, access_source, default_access='allow'): self.default_rule['access'] = default_access self.default_rule['default'] = 'true' + self.embargo = self.parse_embargo(embargo) + + def parse_embargo(self, embargo): + if not embargo: + return None + + value = embargo.get('before') + if value: + embargo['before'] = timestamp_to_datetime(str(value)) + + value = embargo.get('after') + if value: + embargo['after'] = timestamp_to_datetime(str(value)) + + value = embargo.get('older') + if value: + delta = relativedelta( + years=value.get('years', 0), + months=value.get('months', 0), + weeks=value.get('weeks', 0), + days=value.get('days', 0)) + + embargo['older'] = delta + + value = embargo.get('newer') + if value: + delta = relativedelta( + years=value.get('years', 0), + months=value.get('months', 0), + weeks=value.get('weeks', 0), + days=value.get('days', 0)) + + embargo['newer'] = delta + + return embargo + + def check_embargo(self, url, ts): + if not self.embargo: + return None + + dt = timestamp_to_datetime(ts) + access = self.embargo.get('access', 'exclude') + + # embargo before + before = self.embargo.get('before') + if before: + print(dt, before) + return access if dt < before else None + + # embargo after + after = self.embargo.get('after') + if after: + return access if dt > after else None + + # embargo if newser than + newer = self.embargo.get('newer') + if newer: + actual = datetime.utcnow() - newer + return access if actual < dt else None + + # embargo if older than + older = self.embargo.get('older') + if older: + actual = datetime.utcnow() - older + return access if actual > dt else None + def create_access_aggregator(self, source_files): """Creates a new AccessRulesAggregator using the supplied list of access control file names @@ -139,13 +209,15 @@ def create_access_source(self, filename): else: raise Exception('Invalid Access Source: ' + filename) - def find_access_rule(self, url, ts=None, urlkey=None, collection=None): + def find_access_rule(self, url, ts=None, urlkey=None, collection=None, acl_user=None): """Attempts to find the access control rule for the supplied URL otherwise returns the default rule :param str url: The URL for the rule to be found :param str|None ts: A timestamp (not used) :param str|None urlkey: The access control url key + :param str|None collection: The collection, if any + :param str|None acl_user: The access control user, if any :return: The access control rule for the supplied URL if one exists otherwise the default rule :rtype: CDXObject @@ -167,6 +239,9 @@ def find_access_rule(self, url, ts=None, urlkey=None, collection=None): tld = key.split(b',')[0] + last_obj = None + last_key = None + for acl in acl_iter: # skip empty/invalid lines @@ -174,62 +249,97 @@ def find_access_rule(self, url, ts=None, urlkey=None, collection=None): continue acl_key = acl.split(b' ')[0] + acl_obj = None + + if acl_key != last_key and last_obj: + return last_obj if key_exact == acl_key: - return CDXObject(acl) + acl_obj = CDXObject(acl) if key.startswith(acl_key): - return CDXObject(acl) + acl_obj = CDXObject(acl) + + if acl_obj: + user = acl_obj.get('user') + if user == acl_user: + return acl_obj + elif not user: + last_key = acl_key + last_obj = acl_obj # if acl key already less than first tld, # no match can be found if acl_key < tld: break - return self.default_rule + return last_obj if last_obj else self.default_rule - def __call__(self, res): + def __call__(self, res, acl_user): """Wraps the cdx iter in the supplied tuple returning a the wrapped cdx iter and the other members of the supplied tuple in same order :param tuple res: The result tuple + :param str acl_user: The user associated with this request (optional) :return: An tuple """ cdx_iter, errs = res - return self.wrap_iter(cdx_iter), errs + return self.wrap_iter(cdx_iter, acl_user), errs - def wrap_iter(self, cdx_iter): + def wrap_iter(self, cdx_iter, acl_user): """Wraps the supplied cdx iter and yields cdx objects that contain the access control results for the cdx object being yielded :param cdx_iter: The cdx object iterator to be wrapped + :param str acl_user: The user associated with this request (optional) :return: The wrapped cdx object iterator """ last_rule = None last_url = None + last_user = None + rule = None for cdx in cdx_iter: url = cdx.get('url') + timestamp = cdx.get('timestamp') + # if no url, possible idx or other object, don't apply any checks and pass through if not url: yield cdx continue - # TODO: optimization until date range support is included - if url == last_url: - rule = last_rule - else: - rule = self.find_access_rule(url, cdx.get('timestamp'), cdx.get('urlkey'), - cdx.get('source-coll')) + access = None + if self.aggregator: + # TODO: optimization until date range support is included + if url == last_url and acl_user == last_user: + rule = last_rule + else: + rule = self.find_access_rule(url, timestamp, + cdx.get('urlkey'), + cdx.get('source-coll'), + acl_user) + + access = rule.get('access', 'exclude') + + if access != 'allow_ignore_embargo' and access != 'exclude': + embargo_access = self.check_embargo(url, timestamp) + if embargo_access and embargo_access != 'allow': + access = embargo_access - access = rule.get('access', 'exclude') if access == 'exclude': continue + if not access: + access = self.default_rule['access'] + + if access == 'allow_ignore_embargo': + access = 'allow' + cdx['access'] = access yield cdx last_rule = rule last_url = url + last_user = acl_user diff --git a/pywb/warcserver/handlers.py b/pywb/warcserver/handlers.py index 70a2ffc3e..0abd5466c 100644 --- a/pywb/warcserver/handlers.py +++ b/pywb/warcserver/handlers.py @@ -66,8 +66,10 @@ def _load_index_source(self, params): cdx_iter = self.fuzzy(self.index_source, params) + acl_user = params['_input_req'].env.get("HTTP_X_PYWB_ACL_USER") + if self.access_checker: - cdx_iter = self.access_checker(cdx_iter) + cdx_iter = self.access_checker(cdx_iter, acl_user) return cdx_iter diff --git a/pywb/warcserver/index/fuzzymatcher.py b/pywb/warcserver/index/fuzzymatcher.py index 178c2ce43..dac755d90 100644 --- a/pywb/warcserver/index/fuzzymatcher.py +++ b/pywb/warcserver/index/fuzzymatcher.py @@ -209,6 +209,10 @@ def match_general_fuzzy_query(self, url, urlkey, cdx, rx_cache): if mime and mime in self.default_filters['mimes']: check_query = True + # also check query if has method (non-GET request) or requestBody is set + elif cdx.get('requestBody') or cdx.get('method'): + check_query = True + # if check_query, ensure matched url starts with original prefix, only differs by query if check_query: if cdx['url'] == url_no_query or cdx['url'].startswith(url_no_query + '?'): diff --git a/pywb/warcserver/index/indexsource.py b/pywb/warcserver/index/indexsource.py index e5e3f7bb6..ced10f15e 100644 --- a/pywb/warcserver/index/indexsource.py +++ b/pywb/warcserver/index/indexsource.py @@ -248,7 +248,7 @@ def load_index(self, params): try: limit = params.get('limit') if limit: - query = 'limit: {0} '.format(limit) + query + query = 'limit:{0} '.format(limit) + query # OpenSearch API requires double-escaping # TODO: add option to not double escape if needed diff --git a/pywb/warcserver/index/test/test_xmlquery_indexsource.py b/pywb/warcserver/index/test/test_xmlquery_indexsource.py index 63f832cea..3986d11e3 100644 --- a/pywb/warcserver/index/test/test_xmlquery_indexsource.py +++ b/pywb/warcserver/index/test/test_xmlquery_indexsource.py @@ -78,7 +78,7 @@ def test_exact_query(self): com,example)/ 20180216200300 example.warc.gz""" assert(key_ts_res(reslist) == expected) assert(errs == {}) - assert query_url == 'http://localhost:8080/path?q=limit%3A+100+type%3Aurlquery+url%3Ahttp%253A%252F%252Fexample.com%252F' + assert query_url == 'http://localhost:8080/path?q=limit%3A100+type%3Aurlquery+url%3Ahttp%253A%252F%252Fexample.com%252F' assert reslist[0]['length'] == '123' assert 'length' not in reslist[1] diff --git a/pywb/warcserver/warcserver.py b/pywb/warcserver/warcserver.py index a67286716..e4abc7fe3 100644 --- a/pywb/warcserver/warcserver.py +++ b/pywb/warcserver/warcserver.py @@ -210,6 +210,7 @@ def load_coll(self, name, coll_config): archive_paths = None acl_paths = None default_access = self.default_access + embargo = None elif isinstance(coll_config, dict): index = coll_config.get('index') if not index: @@ -217,6 +218,7 @@ def load_coll(self, name, coll_config): archive_paths = coll_config.get('archive_paths') acl_paths = coll_config.get('acl_paths') default_access = coll_config.get('default_access', self.default_access) + embargo = coll_config.get('embargo') else: raise Exception('collection config must be string or dict') @@ -245,8 +247,8 @@ def load_coll(self, name, coll_config): # ACCESS CONFIG access_checker = None - if acl_paths: - access_checker = AccessChecker(acl_paths, default_access) + if acl_paths or embargo: + access_checker = AccessChecker(acl_paths, default_access, embargo) return DefaultResourceHandler(agg, archive_paths, rules_file=self.rules_file, diff --git a/requirements.txt b/requirements.txt index 0c3e0af2d..7f3d3401e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,3 +15,4 @@ wsgiprox>=1.5.1 fakeredis<1.0 tldextract babel +python-dateutil diff --git a/sample-deploy/pywb-apache.conf b/sample-deploy/pywb-apache.conf index 1fdfab51c..96c5ff5b2 100644 --- a/sample-deploy/pywb-apache.conf +++ b/sample-deploy/pywb-apache.conf @@ -14,4 +14,13 @@ # required: proxy pass to pywb ProxyPass /wayback uwsgi://pywb:8081/ + # optional: set custom header based on IP ranges + + RequestHeader set X-Pywb-ACL-User staff + + # ensure header is cleared if no match + + RequestHeader set X-Pywb-ACL-User "" + + diff --git a/sample-deploy/pywb-nginx.conf b/sample-deploy/pywb-nginx.conf index dd22ea698..23c553379 100644 --- a/sample-deploy/pywb-nginx.conf +++ b/sample-deploy/pywb-nginx.conf @@ -1,5 +1,18 @@ # nginx config for running under /wayback/ prefix + +# set acl_user, defaulting to empty (any public user) +geo $acl_user { + # ensure user is set to empty by default + default ""; + + # optional: add IP ranges to allow privileged access + 127.0.0.1 "staff"; + 192.168.0.0/24 "staff"; +} + + + server { listen 80; @@ -14,8 +27,12 @@ server { uwsgi_pass pywb:8081; + include uwsgi_params; uwsgi_param UWSGI_SCHEME $scheme; + + # pass acl_user (which should be empty by default) + uwsgi_param HTTP_X_PYWB_ACL_USER $acl_user; } } diff --git a/sample_archive/access/pywb.aclj b/sample_archive/access/pywb.aclj index 84b7e417e..44382df37 100644 --- a/sample_archive/access/pywb.aclj +++ b/sample_archive/access/pywb.aclj @@ -1,7 +1,12 @@ org,iana)/exact/match/first/line/aclj### - {"access": "allow", "url": "https://www.iana.org/exact/match/first/line/aclj/"} org,iana)/about - {"access": "block"} +org,iana)/about - {"access": "allow", "user": "staff"} org,iana)/_css/2013.1/fonts/opensans-semibold.ttf - {"access": "allow"} org,iana)/_css - {"access": "exclude"} org,iana)/### - {"access": "allow"} org,iana)/ - {"access": "exclude"} org,example)/?example=1 - {"access": "block"} +com,example)/?example=2 - {"access": "allow_ignore_embargo"} +com,example)/?example=1 - {"access": "allow_ignore_embargo", "user": "staff2"} +com,example)/?example=1 - {"access": "allow", "user": "staff"} +com,example)/ - {"access": "allow"} diff --git a/tests/config_test_access.yaml b/tests/config_test_access.yaml index 49c4220c3..8fb352f7c 100644 --- a/tests/config_test_access.yaml +++ b/tests/config_test_access.yaml @@ -24,4 +24,44 @@ collections: default_access: block + pywb-embargo-before: + index_paths: ./sample_archive/cdx/ + archive_paths: ./sample_archive/warcs/ + embargo: + before: '2014012700' + + pywb-embargo-after: + index_paths: ./sample_archive/cdx/ + archive_paths: ./sample_archive/warcs/ + embargo: + after: '2014012700' + + pywb-embargo-older: + index_paths: ./sample_archive/cdx/ + archive_paths: ./sample_archive/warcs/ + embargo: + older: + years: 1 + months: 6 + + pywb-embargo-newer: + index_paths: ./sample_archive/cdx/ + archive_paths: ./sample_archive/warcs/ + embargo: + newer: + years: 1 + months: 6 + + pywb-embargo-acl: + index_paths: ./sample_archive/cdx/ + archive_paths: ./sample_archive/warcs/ + embargo: + older: + years: 1 + + acl_paths: + - ./sample_archive/access/pywb.aclj + + + diff --git a/tests/test_acl.py b/tests/test_acl.py index 2554d2e51..5ed532d18 100644 --- a/tests/test_acl.py +++ b/tests/test_acl.py @@ -40,6 +40,13 @@ def test_blocked_url(self): assert 'Access Blocked' in resp.text + def test_allow_via_acl_header(self): + resp = self.query('http://www.iana.org/about/') + + assert len(resp.text.splitlines()) == 1 + + resp = self.testapp.get('/pywb/mp_/http://www.iana.org/about/', headers={"X-Pywb-Acl-User": "staff"}, status=200) + def test_allowed_more_specific(self): resp = self.query('http://www.iana.org/_css/2013.1/fonts/opensans-semibold.ttf') diff --git a/tests/test_acl_manager.py b/tests/test_acl_manager.py index 16f2239dc..4e732be1c 100644 --- a/tests/test_acl_manager.py +++ b/tests/test_acl_manager.py @@ -40,6 +40,16 @@ def test_acl_add_surt(self): assert fh.read() == """\ com,example, - {"access": "exclude", "url": "com,example,"} com,example)/ - {"access": "allow", "url": "http://example.com/"} +""" + + def test_acl_add_with_user(self): + wb_manager(['acl', 'add', self.acl_filename, 'http://example.com/', 'block', '-u', 'public']) + + with open(self.acl_filename, 'rt') as fh: + assert fh.read() == """\ +com,example, - {"access": "exclude", "url": "com,example,"} +com,example)/ - {"access": "block", "url": "http://example.com/", "user": "public"} +com,example)/ - {"access": "allow", "url": "http://example.com/"} """ def test_acl_list(self, capsys): @@ -51,6 +61,7 @@ def test_acl_list(self, capsys): Rules for %s from %s: com,example, - {"access": "exclude", "url": "com,example,"} +com,example)/ - {"access": "block", "url": "http://example.com/", "user": "public"} com,example)/ - {"access": "allow", "url": "http://example.com/"} """ % (self.acl_filename, self.acl_filename) @@ -71,16 +82,63 @@ def test_acl_match(self, capsys): com,example, - {"access": "exclude", "url": "com,example,"} +""" + + def test_acl_match_user(self, capsys): + wb_manager(['acl', 'match', self.acl_filename, 'http://example.com/foo', '-u', 'public']) + + out, err = capsys.readouterr() + + assert out == """\ +Matched rule: + + com,example)/ - {"access": "block", "url": "http://example.com/", "user": "public"} + +""" + + def test_acl_match_unknown_user(self, capsys): + wb_manager(['acl', 'match', self.acl_filename, 'http://example.com/foo', '-u', 'data']) + + out, err = capsys.readouterr() + + assert out == """\ +Matched rule: + + com,example)/ - {"access": "allow", "url": "http://example.com/"} + +""" + + def test_acl_match_default_user(self, capsys): + wb_manager(['acl', 'match', self.acl_filename, 'http://example.com/foo']) + + out, err = capsys.readouterr() + + assert out == """\ +Matched rule: + + com,example)/ - {"access": "allow", "url": "http://example.com/"} + """ def test_remove_acl(self): wb_manager(['acl', 'remove', self.acl_filename, 'com,example,']) + with open(self.acl_filename, 'rt') as fh: + assert fh.read() == """\ +com,example)/ - {"access": "block", "url": "http://example.com/", "user": "public"} +com,example)/ - {"access": "allow", "url": "http://example.com/"} +""" + + def test_remove_acl_user(self): + wb_manager(['acl', 'remove', self.acl_filename, 'com,example)/', '-u', 'public']) + with open(self.acl_filename, 'rt') as fh: assert fh.read() == """\ com,example)/ - {"access": "allow", "url": "http://example.com/"} """ + + def test_acl_add_exact(self): wb_manager(['acl', 'add', '--exact-match', self.acl_filename, 'example.com', 'block']) diff --git a/tests/test_embargo.py b/tests/test_embargo.py new file mode 100644 index 000000000..4c1ab21e2 --- /dev/null +++ b/tests/test_embargo.py @@ -0,0 +1,56 @@ +from .base_config_test import BaseConfigTest, fmod + +import webtest +import os + +from six.moves.urllib.parse import urlencode + + +# ============================================================================ +class TestEmbargoApp(BaseConfigTest): + @classmethod + def setup_class(cls): + super(TestEmbargoApp, cls).setup_class('config_test_access.yaml') + + def test_embargo_before(self): + resp = self.testapp.get('/pywb-embargo-before/20140126201054mp_/http://www.iana.org/domains/reserved', status=404) + + resp = self.testapp.get('/pywb-embargo-before/20140127mp_/http://example.com/', status=200) + assert resp.headers['Content-Location'] == 'http://localhost:80/pywb-embargo-before/20140127171251mp_/http://example.com' + + def test_embargo_after(self): + resp = self.testapp.get('/pywb-embargo-after/20140126201054mp_/http://www.iana.org/domains/reserved', status=200) + + resp = self.testapp.get('/pywb-embargo-after/20140127mp_/http://example.com/', status=200) + assert resp.headers['Content-Location'] == 'http://localhost:80/pywb-embargo-after/20130729195151mp_/http://test@example.com/' + + def test_embargo_older(self): + resp = self.testapp.get('/pywb-embargo-older/20140126201054mp_/http://www.iana.org/domains/reserved', status=404) + + resp = self.testapp.get('/pywb-embargo-older/20140127mp_/http://example.com/', status=404) + + def test_embargo_newer(self): + resp = self.testapp.get('/pywb-embargo-newer/20140126201054mp_/http://www.iana.org/domains/reserved', status=200) + + resp = self.testapp.get('/pywb-embargo-newer/20140127mp_/http://example.com/', status=200) + assert resp.headers['Content-Location'] == 'http://localhost:80/pywb-embargo-newer/20140127171251mp_/http://example.com' + + def test_embargo_ignore_acl(self): + # embargoed + resp = self.testapp.get('/pywb-embargo-acl/20140126201054mp_/http://example.com/', status=404) + + # ignore embargo + resp = self.testapp.get('/pywb-embargo-acl/20140126201054mp_/http://example.com/?example=2', status=200) + + + def test_embargo_ignore_acl_with_header_only(self): + # ignore embargo with custom header only + headers = {"X-Pywb-ACL-User": "staff2"} + resp = self.testapp.get('/pywb-embargo-acl/20140126201054mp_/http://example.com/?example=1', status=200, headers=headers) + + resp = self.testapp.get('/pywb-embargo-acl/20140126201054mp_/http://example.com/?example=1', status=404) + + + + + diff --git a/wombat b/wombat index 1e1cfc399..14c167613 160000 --- a/wombat +++ b/wombat @@ -1 +1 @@ -Subproject commit 1e1cfc399fc194f04651416f89805090f2068948 +Subproject commit 14c167613648c8a1679e6c31e2ebd5284ef94c81