add option to disable mixed content security, workaround for ajax restrictions

This commit is contained in:
ccd0 2014-08-03 19:53:01 -07:00
parent e70cdc620a
commit 790a62d1bd
5 changed files with 96 additions and 56 deletions

View File

@ -54,8 +54,8 @@ Redirect =
# For fuuka-based archives:
# https://github.com/eksopl/fuuka/issues/27
protocol = Redirect.protocol archive
return '' unless protocol is 'https://' or location.protocol is 'http:'
URL = new String "#{protocol}#{archive.domain}/_/api/chan/post/?board=#{boardID}&num=#{postID}"
return '' unless Redirect.securityCheck URL
URL.archive = archive
URL
@ -76,10 +76,14 @@ Redirect =
"#{boardID}/?task=search2&search_#{if type is 'image' then 'media_hash' else type}=#{value}"
"#{Redirect.protocol archive}#{archive.domain}/#{path}"
securityCheck: (URL) ->
/^https:\/\//.test(URL) or
location.protocol is 'http:' or
Conf['Allow Mixed Content from Archives']
navigate: (URL, alternative) ->
if URL and (
/^https:\/\//.test(URL) or
location.protocol is 'http:' or
Redirect.securityCheck(URL) or
confirm "Redirect to #{URL}?\n\nYour connection will not be encrypted."
)
location.replace URL

View File

@ -29,6 +29,10 @@ Config =
true
'Redirect dead threads and images.'
]
'Allow Mixed Content from Archives': [
false
'Permit warningless access to HTTP-only archives from HTTPS pages.'
]
'Keybinds': [
true
'Bind actions to keyboard shortcuts.'

View File

@ -1,46 +1,73 @@
CrossOrigin = do ->
CrossOrigin =
file: do ->
makeBlob = (urlBlob, contentType, contentDisposition, url) ->
name = url.match(/([^\/]+)\/*$/)?[1]
mime = contentType?.match(/[^;]*/)[0] or 'application/octet-stream'
match =
contentDisposition?.match(/\bfilename\s*=\s*"((\\"|[^"])+)"/i)?[1] or
contentType?.match(/\bname\s*=\s*"((\\"|[^"])+)"/i)?[1]
if match
name = match.replace /\\"/g, '"'
blob = new Blob([urlBlob], {type: mime})
blob.name = name
blob
makeBlob = (urlBlob, contentType, contentDisposition, url) ->
name = url.match(/([^\/]+)\/*$/)?[1]
mime = contentType?.match(/[^;]*/)[0] or 'application/octet-stream'
match =
contentDisposition?.match(/\bfilename\s*=\s*"((\\"|[^"])+)"/i)?[1] or
contentType?.match(/\bname\s*=\s*"((\\"|[^"])+)"/i)?[1]
if match
name = match.replace /\\"/g, '"'
blob = new Blob([urlBlob], {type: mime})
blob.name = name
blob
(url, cb) ->
<% if (type === 'crx') { %>
$.ajax url,
responseType: 'blob'
onload: ->
return cb null unless @readyState is @DONE and @status is 200
contentType = @getResponseHeader 'Content-Type'
contentDisposition = @getResponseHeader 'Content-Disposition'
cb (makeBlob @response, contentType, contentDisposition, url)
onerror: ->
cb null
<% } %>
<% if (type === 'userscript') { %>
GM_xmlhttpRequest
method: "GET"
url: url
overrideMimeType: "text/plain; charset=x-user-defined"
onload: (xhr) ->
r = xhr.responseText
data = new Uint8Array r.length
i = 0
while i < r.length
data[i] = r.charCodeAt i
i++
contentType = xhr.responseHeaders.match(/Content-Type:\s*(.*)/i)?[1]
contentDisposition = xhr.responseHeaders.match(/Content-Disposition:\s*(.*)/i)?[1]
cb (makeBlob data, contentType, contentDisposition, url)
onerror: ->
cb null
<% } %>
file = (url, cb) ->
<% if (type === 'crx') { %>
$.ajax url,
responseType: 'blob'
onload: ->
return cb null unless @readyState is @DONE and @status is 200
contentType = @getResponseHeader 'Content-Type'
contentDisposition = @getResponseHeader 'Content-Disposition'
cb (makeBlob @response, contentType, contentDisposition, url)
onerror: ->
cb null
<% } %>
<% if (type === 'userscript') { %>
GM_xmlhttpRequest
method: "GET"
url: url
overrideMimeType: "text/plain; charset=x-user-defined"
onload: (xhr) ->
r = xhr.responseText
data = new Uint8Array r.length
i = 0
while i < r.length
data[i] = r.charCodeAt i
i++
contentType = xhr.responseHeaders.match(/Content-Type:\s*(.*)/i)?[1]
contentDisposition = xhr.responseHeaders.match(/Content-Disposition:\s*(.*)/i)?[1]
cb (makeBlob data, contentType, contentDisposition, url)
onerror: ->
cb null
<% } %>
{file}
json: do ->
callbacks = {}
responses = {}
(url, cb) ->
<% if (type === 'crx') { %>
$.cache url, (-> cb @response), responseType: 'json'
<% } %>
<% if (type === 'userscript') { %>
if responses[url]
cb responses[url]
return
if callbacks[url]
callbacks[url].push cb
return
callbacks[url] = [cb]
GM_xmlhttpRequest
method: "GET"
url: url
onload: (xhr) ->
response = JSON.parse xhr.responseText
cb response for cb in callbacks[url]
delete callbacks[url]
responses[url] = response
onerror: ->
delete callbacks[url]
onabort: ->
delete callbacks[url]
<% } %>

View File

@ -132,20 +132,25 @@ Get =
Get.insert post, root, context
archivedPost: (boardID, postID, root, context) ->
return false unless url = Redirect.to 'post', {boardID, postID}
$.cache url,
-> Get.parseArchivedPost @, boardID, postID, root, context
,
responseType: 'json'
withCredentials: url.archive.withCredentials
return true
parseArchivedPost: (req, boardID, postID, root, context) ->
if /^https:\/\//.test(URL) or location.protocol is 'http:'
$.cache url,
-> Get.parseArchivedPost @response, boardID, postID, root, context
,
responseType: 'json'
withCredentials: url.archive.withCredentials
return true
else if Conf['Allow Mixed Content from Archives']
CrossOrigin.json url, (response) ->
Get.parseArchivedPost response, boardID, postID, root, context
return true
return false
parseArchivedPost: (data, boardID, postID, root, context) ->
# In case of multiple callbacks for the same request,
# don't parse the same original post more than once.
if post = g.posts["#{boardID}.#{postID}"]
Get.insert post, root, context
return
data = req.response
if data.error
$.addClass root, 'warning'
root.textContent = data.error

View File

@ -12,7 +12,7 @@ ImageCommon =
URL = Redirect.to 'file',
boardID: post.board.ID
filename: src[src.length - 1]
unless URL and (/^https:\/\//.test(URL) or location.protocol is 'http:')
unless URL and Redirect.securityCheck URL
URL = null
return cb URL if (post.isDead or post.file.isDead) and file.src.split('/')[2] is 'i.4cdn.org'