clear-site-data-cache.py (7922B)
1 """ 2 Loaded in Step 2/4/Optional 6 (/clear-site-data/clear-cache.https.html) 3 Sending Message for Step 3/5/Optional 7 (/clear-site-data/clear-cache.https.html) 4 """ 5 import uuid 6 import random 7 8 def generate_png(width, height, color=(0, 0, 0)): 9 import zlib 10 import struct 11 def chunk(chunk_type, data): 12 return ( 13 struct.pack(">I", len(data)) + 14 chunk_type + 15 data + 16 struct.pack(">I", zlib.crc32(chunk_type + data) & 0xffffffff) 17 ) 18 19 # PNG signature 20 png = b"\x89PNG\r\n\x1a\n" 21 22 # IHDR chunk 23 ihdr = struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0) 24 png += chunk(b'IHDR', ihdr) 25 26 # IDAT chunk: RGB pixels 27 row = b'\x00' + bytes(color * width) 28 raw = row * height 29 idat = zlib.compress(raw) 30 png += chunk(b'IDAT', idat) 31 32 # IEND chunk 33 png += chunk(b'IEND', b'') 34 return png 35 36 def main(request, response): 37 # type of response: 38 # - General purpose: returns random uuid or forwards uuid from iframe 39 # - "single_html": Main page html file with a different postMessage uuid on each response 40 # - Pages for simple testing normal http cache: 41 # - "json": Json that always responds with a different uuid in a single-element array 42 # - "html_embed_json": Main page html that embeds a cachable version of the above json 43 # - Pages for testing specialized caches 44 # - "image": Image that returns random dimensions up to 1024x1024 each time 45 # - "html_embed_image": Main page html that embeds a cachable version of the above image 46 # - "css": Style sheet with random uuid variable 47 # - "html_embed_css": Main page html that embeds a cachable version of the above css 48 # - "js": Script that returns a different uuid each time 49 # - "html_embed_js": Main page html that embeds a cachable version of the above js file 50 response_type = request.GET.first(b"response") 51 52 cache_helper = request.GET.first(b"cache_helper") 53 54 # force enable caching when present or force disable if not 55 cache = b"cache" in request.GET 56 clear = None 57 if b"clear" in request.GET: 58 clear = request.GET.first(b"clear") 59 if b"clear_first" in request.GET: 60 if request.server.stash.take(cache_helper) is None: 61 clear = request.GET.first(b"clear_first") 62 request.server.stash.put(cache_helper, ()) 63 64 headers = [] 65 if response_type == b"json": 66 headers += [(b"Content-Type", b"application/json")] 67 elif response_type == b"image": 68 headers += [(b"Content-Type", b"image/png")] 69 elif response_type == b"css": 70 headers += [(b"Content-Type", b"text/css")] 71 elif response_type == b"js": 72 headers += [(b"Content-Type", b"text/javascript")] 73 else: 74 headers += [(b"Content-Type", b"text/html")] 75 76 if cache: 77 headers += [(b"cache-control", b"public, max-age=31536000, immutable")] 78 else: 79 headers += [(b"cache-control", b"no-store")] 80 81 if clear is not None: 82 if clear == b"all": 83 headers += [(b"Clear-Site-Data", b'"*"')] 84 else: 85 headers += [(b"Clear-Site-Data", b'"' + clear + b'"')] 86 87 if response_type == b"single_html": 88 iframe = "" 89 if b"iframe" in request.GET: 90 # forward message from iframe to opener 91 iframe_url = request.GET.first(b"iframe").decode() 92 content = f''' 93 <script> 94 // forward iframe uuid to opener 95 window.addEventListener('message', function(event) {{ 96 if(window.opener) {{ 97 window.opener.postMessage(event.data, "*"); 98 }} else {{ 99 window.parent.postMessage(event.data, "*"); 100 }} 101 window.close(); 102 }}); 103 </script> 104 <br> 105 {request.url}<br> 106 {iframe_url}<br> 107 <iframe src="{iframe_url}"></iframe> 108 </body> 109 ''' 110 else: 111 # send unique UUID. Cache got cleared when uuids don't match. 112 u = uuid.uuid4() 113 content = f''' 114 <script> 115 if(window.opener) {{ 116 window.opener.postMessage("{u}", "*"); 117 }} else {{ 118 window.parent.postMessage("{u}", "*"); 119 }} 120 window.close(); 121 </script> 122 <body> 123 {request.url} 124 </body>''' 125 elif response_type == b"json": 126 # send unique UUID. helper for below "html_embed_json" 127 content = f'''["{uuid.uuid4()}"]''' 128 elif response_type == b"html_embed_json": 129 url = request.url_parts.path + "?response=json&cache&cache_helper=" + cache_helper.decode() 130 content = f''' 131 <script> 132 fetch("{url}") 133 .then(response => response.json()) 134 .then(uuid => {{ 135 window.opener.postMessage(uuid[0], "*"); 136 window.close(); 137 }}); 138 </script> 139 <body> 140 {request.url}<br> 141 {url} 142 </body>''' 143 elif response_type == b"image": 144 # send uniquely sized images, because that info can be retrived from html and definitly using the image cache 145 # helper for below "html_embed_image" 146 content = generate_png(random.randint(1, 1024), random.randint(1, 1024)) 147 elif response_type == b"html_embed_image": 148 urls = [request.url_parts.path + "?response=image&cache&cache_helper=" + cache_helper.decode() + "&img=" + str(i) for i in range(2)] 149 content = f''' 150 <!DOCTYPE html> 151 <script> 152 addEventListener("load", () => {{ 153 let img1 = document.getElementById("randomess1"); 154 let img2 = document.getElementById("randomess2"); 155 let id = img1.naturalWidth + "x" + img1.naturalHeight; 156 id += "-" + img2.naturalWidth + "x" + img2.naturalHeight 157 window.opener.postMessage(id, "*"); 158 window.close(); 159 }}) 160 </script> 161 <body> 162 {request.url}<br> 163 <img id="randomess1" src="{urls[0]}"></img><br> 164 <img id="randomess2" src="{urls[1]}"></img><br> 165 </body>''' 166 elif response_type == b"css": 167 # send unique UUID. helper for below "html_embed_css" 168 content = f''' 169 :root {{ 170 --uuid: "{uuid.uuid4()}" 171 }}''' 172 elif response_type == b"html_embed_css": 173 url = request.url_parts.path + "?response=css&cache&cache_helper=" + cache_helper.decode() 174 content = f''' 175 <!DOCTYPE html> 176 <link rel="stylesheet" href="{url}"> 177 <script> 178 let computed = getComputedStyle(document.documentElement); 179 let uuid = computed.getPropertyValue("--uuid").trim().replaceAll('"', ''); 180 window.opener.postMessage(uuid, "*"); 181 window.close(); 182 </script> 183 <body> 184 {request.url}<br> 185 {url} 186 </body>''' 187 elif response_type == b"js": 188 # send unique UUID. helper for below "html_embed_js" 189 content = f''' 190 window.opener.postMessage("{uuid.uuid4()}", "*"); 191 window.close(); 192 ''' 193 elif response_type == b"html_embed_js": 194 url = request.url_parts.path + "?response=js&cache&cache_helper=" + cache_helper.decode() 195 content = f''' 196 <script src="{url}"></script> 197 <body> 198 {request.url}<br> 199 {url} 200 </body>''' 201 202 return 200, headers, content