add option to disable mixed content security, workaround for ajax restrictions
This commit is contained in:
parent
e70cdc620a
commit
790a62d1bd
@ -54,8 +54,8 @@ Redirect =
|
|||||||
# For fuuka-based archives:
|
# For fuuka-based archives:
|
||||||
# https://github.com/eksopl/fuuka/issues/27
|
# https://github.com/eksopl/fuuka/issues/27
|
||||||
protocol = Redirect.protocol archive
|
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}"
|
URL = new String "#{protocol}#{archive.domain}/_/api/chan/post/?board=#{boardID}&num=#{postID}"
|
||||||
|
return '' unless Redirect.securityCheck URL
|
||||||
URL.archive = archive
|
URL.archive = archive
|
||||||
URL
|
URL
|
||||||
|
|
||||||
@ -76,10 +76,14 @@ Redirect =
|
|||||||
"#{boardID}/?task=search2&search_#{if type is 'image' then 'media_hash' else type}=#{value}"
|
"#{boardID}/?task=search2&search_#{if type is 'image' then 'media_hash' else type}=#{value}"
|
||||||
"#{Redirect.protocol archive}#{archive.domain}/#{path}"
|
"#{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) ->
|
navigate: (URL, alternative) ->
|
||||||
if URL and (
|
if URL and (
|
||||||
/^https:\/\//.test(URL) or
|
Redirect.securityCheck(URL) or
|
||||||
location.protocol is 'http:' or
|
|
||||||
confirm "Redirect to #{URL}?\n\nYour connection will not be encrypted."
|
confirm "Redirect to #{URL}?\n\nYour connection will not be encrypted."
|
||||||
)
|
)
|
||||||
location.replace URL
|
location.replace URL
|
||||||
|
|||||||
@ -29,6 +29,10 @@ Config =
|
|||||||
true
|
true
|
||||||
'Redirect dead threads and images.'
|
'Redirect dead threads and images.'
|
||||||
]
|
]
|
||||||
|
'Allow Mixed Content from Archives': [
|
||||||
|
false
|
||||||
|
'Permit warningless access to HTTP-only archives from HTTPS pages.'
|
||||||
|
]
|
||||||
'Keybinds': [
|
'Keybinds': [
|
||||||
true
|
true
|
||||||
'Bind actions to keyboard shortcuts.'
|
'Bind actions to keyboard shortcuts.'
|
||||||
|
|||||||
@ -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) ->
|
(url, cb) ->
|
||||||
name = url.match(/([^\/]+)\/*$/)?[1]
|
<% if (type === 'crx') { %>
|
||||||
mime = contentType?.match(/[^;]*/)[0] or 'application/octet-stream'
|
$.ajax url,
|
||||||
match =
|
responseType: 'blob'
|
||||||
contentDisposition?.match(/\bfilename\s*=\s*"((\\"|[^"])+)"/i)?[1] or
|
onload: ->
|
||||||
contentType?.match(/\bname\s*=\s*"((\\"|[^"])+)"/i)?[1]
|
return cb null unless @readyState is @DONE and @status is 200
|
||||||
if match
|
contentType = @getResponseHeader 'Content-Type'
|
||||||
name = match.replace /\\"/g, '"'
|
contentDisposition = @getResponseHeader 'Content-Disposition'
|
||||||
blob = new Blob([urlBlob], {type: mime})
|
cb (makeBlob @response, contentType, contentDisposition, url)
|
||||||
blob.name = name
|
onerror: ->
|
||||||
blob
|
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) ->
|
json: do ->
|
||||||
<% if (type === 'crx') { %>
|
callbacks = {}
|
||||||
$.ajax url,
|
responses = {}
|
||||||
responseType: 'blob'
|
(url, cb) ->
|
||||||
onload: ->
|
<% if (type === 'crx') { %>
|
||||||
return cb null unless @readyState is @DONE and @status is 200
|
$.cache url, (-> cb @response), responseType: 'json'
|
||||||
contentType = @getResponseHeader 'Content-Type'
|
<% } %>
|
||||||
contentDisposition = @getResponseHeader 'Content-Disposition'
|
<% if (type === 'userscript') { %>
|
||||||
cb (makeBlob @response, contentType, contentDisposition, url)
|
if responses[url]
|
||||||
onerror: ->
|
cb responses[url]
|
||||||
cb null
|
return
|
||||||
<% } %>
|
if callbacks[url]
|
||||||
<% if (type === 'userscript') { %>
|
callbacks[url].push cb
|
||||||
GM_xmlhttpRequest
|
return
|
||||||
method: "GET"
|
callbacks[url] = [cb]
|
||||||
url: url
|
GM_xmlhttpRequest
|
||||||
overrideMimeType: "text/plain; charset=x-user-defined"
|
method: "GET"
|
||||||
onload: (xhr) ->
|
url: url
|
||||||
r = xhr.responseText
|
onload: (xhr) ->
|
||||||
data = new Uint8Array r.length
|
response = JSON.parse xhr.responseText
|
||||||
i = 0
|
cb response for cb in callbacks[url]
|
||||||
while i < r.length
|
delete callbacks[url]
|
||||||
data[i] = r.charCodeAt i
|
responses[url] = response
|
||||||
i++
|
onerror: ->
|
||||||
contentType = xhr.responseHeaders.match(/Content-Type:\s*(.*)/i)?[1]
|
delete callbacks[url]
|
||||||
contentDisposition = xhr.responseHeaders.match(/Content-Disposition:\s*(.*)/i)?[1]
|
onabort: ->
|
||||||
cb (makeBlob data, contentType, contentDisposition, url)
|
delete callbacks[url]
|
||||||
onerror: ->
|
<% } %>
|
||||||
cb null
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
{file}
|
|
||||||
|
|||||||
@ -132,20 +132,25 @@ Get =
|
|||||||
Get.insert post, root, context
|
Get.insert post, root, context
|
||||||
archivedPost: (boardID, postID, root, context) ->
|
archivedPost: (boardID, postID, root, context) ->
|
||||||
return false unless url = Redirect.to 'post', {boardID, postID}
|
return false unless url = Redirect.to 'post', {boardID, postID}
|
||||||
$.cache url,
|
if /^https:\/\//.test(URL) or location.protocol is 'http:'
|
||||||
-> Get.parseArchivedPost @, boardID, postID, root, context
|
$.cache url,
|
||||||
,
|
-> Get.parseArchivedPost @response, boardID, postID, root, context
|
||||||
responseType: 'json'
|
,
|
||||||
withCredentials: url.archive.withCredentials
|
responseType: 'json'
|
||||||
return true
|
withCredentials: url.archive.withCredentials
|
||||||
parseArchivedPost: (req, boardID, postID, root, context) ->
|
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,
|
# In case of multiple callbacks for the same request,
|
||||||
# don't parse the same original post more than once.
|
# don't parse the same original post more than once.
|
||||||
if post = g.posts["#{boardID}.#{postID}"]
|
if post = g.posts["#{boardID}.#{postID}"]
|
||||||
Get.insert post, root, context
|
Get.insert post, root, context
|
||||||
return
|
return
|
||||||
|
|
||||||
data = req.response
|
|
||||||
if data.error
|
if data.error
|
||||||
$.addClass root, 'warning'
|
$.addClass root, 'warning'
|
||||||
root.textContent = data.error
|
root.textContent = data.error
|
||||||
|
|||||||
@ -12,7 +12,7 @@ ImageCommon =
|
|||||||
URL = Redirect.to 'file',
|
URL = Redirect.to 'file',
|
||||||
boardID: post.board.ID
|
boardID: post.board.ID
|
||||||
filename: src[src.length - 1]
|
filename: src[src.length - 1]
|
||||||
unless URL and (/^https:\/\//.test(URL) or location.protocol is 'http:')
|
unless URL and Redirect.securityCheck URL
|
||||||
URL = null
|
URL = null
|
||||||
|
|
||||||
return cb URL if (post.isDead or post.file.isDead) and file.src.split('/')[2] is 'i.4cdn.org'
|
return cb URL if (post.isDead or post.file.isDead) and file.src.split('/')[2] is 'i.4cdn.org'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user