mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-13 20:11:19 -04:00
Initialize snowflake instance with a config
This commit is contained in:
parent
edbbea1d03
commit
2d8a1690ba
11 changed files with 125 additions and 113 deletions
|
@ -11,6 +11,7 @@ FILES = [
|
||||||
'broker.coffee'
|
'broker.coffee'
|
||||||
'ui.coffee'
|
'ui.coffee'
|
||||||
'snowflake.coffee'
|
'snowflake.coffee'
|
||||||
|
'config.coffee'
|
||||||
]
|
]
|
||||||
FILES_SPEC = [
|
FILES_SPEC = [
|
||||||
'spec/util.spec.coffee'
|
'spec/util.spec.coffee'
|
||||||
|
@ -19,6 +20,7 @@ FILES_SPEC = [
|
||||||
'spec/proxypair.spec.coffee'
|
'spec/proxypair.spec.coffee'
|
||||||
'spec/snowflake.spec.coffee'
|
'spec/snowflake.spec.coffee'
|
||||||
'spec/websocket.spec.coffee'
|
'spec/websocket.spec.coffee'
|
||||||
|
'spec/init.spec.coffee'
|
||||||
]
|
]
|
||||||
FILES_ALL = FILES.concat FILES_SPEC
|
FILES_ALL = FILES.concat FILES_SPEC
|
||||||
OUTFILE = 'snowflake.js'
|
OUTFILE = 'snowflake.js'
|
||||||
|
|
|
@ -7,12 +7,14 @@ to get assigned to clients.
|
||||||
|
|
||||||
# Represents a broker running remotely.
|
# Represents a broker running remotely.
|
||||||
class Broker
|
class Broker
|
||||||
@STATUS_OK = 200
|
@STATUS:
|
||||||
@STATUS_GONE = 410
|
OK: 200
|
||||||
@STATUS_GATEWAY_TIMEOUT = 504
|
GONE: 410
|
||||||
|
GATEWAY_TIMEOUT: 504
|
||||||
|
|
||||||
@MESSAGE_TIMEOUT = 'Timed out waiting for a client offer.'
|
@MESSAGE:
|
||||||
@MESSAGE_UNEXPECTED = 'Unexpected status.'
|
TIMEOUT: 'Timed out waiting for a client offer.'
|
||||||
|
UNEXPECTED: 'Unexpected status.'
|
||||||
|
|
||||||
clients: 0
|
clients: 0
|
||||||
|
|
||||||
|
@ -38,15 +40,15 @@ class Broker
|
||||||
xhr.onreadystatechange = ->
|
xhr.onreadystatechange = ->
|
||||||
return if xhr.DONE != xhr.readyState
|
return if xhr.DONE != xhr.readyState
|
||||||
switch xhr.status
|
switch xhr.status
|
||||||
when Broker.STATUS_OK
|
when Broker.STATUS.OK
|
||||||
fulfill xhr.responseText # Should contain offer.
|
fulfill xhr.responseText # Should contain offer.
|
||||||
when Broker.STATUS_GATEWAY_TIMEOUT
|
when Broker.STATUS.GATEWAY_TIMEOUT
|
||||||
reject Broker.MESSAGE_TIMEOUT
|
reject Broker.MESSAGE.TIMEOUT
|
||||||
else
|
else
|
||||||
log 'Broker ERROR: Unexpected ' + xhr.status +
|
log 'Broker ERROR: Unexpected ' + xhr.status +
|
||||||
' - ' + xhr.statusText
|
' - ' + xhr.statusText
|
||||||
snowflake.ui.setStatus ' failure. Please refresh.'
|
snowflake.ui.setStatus ' failure. Please refresh.'
|
||||||
reject Broker.MESSAGE_UNEXPECTED
|
reject Broker.MESSAGE.UNEXPECTED
|
||||||
@_xhr = xhr # Used by spec to fake async Broker interaction
|
@_xhr = xhr # Used by spec to fake async Broker interaction
|
||||||
@_postRequest id, xhr, 'proxy', id
|
@_postRequest id, xhr, 'proxy', id
|
||||||
|
|
||||||
|
@ -59,10 +61,10 @@ class Broker
|
||||||
xhr.onreadystatechange = ->
|
xhr.onreadystatechange = ->
|
||||||
return if xhr.DONE != xhr.readyState
|
return if xhr.DONE != xhr.readyState
|
||||||
switch xhr.status
|
switch xhr.status
|
||||||
when Broker.STATUS_OK
|
when Broker.STATUS.OK
|
||||||
dbg 'Broker: Successfully replied with answer.'
|
dbg 'Broker: Successfully replied with answer.'
|
||||||
dbg xhr.responseText
|
dbg xhr.responseText
|
||||||
when Broker.STATUS_GONE
|
when Broker.STATUS.GONE
|
||||||
dbg 'Broker: No longer valid to reply with answer.'
|
dbg 'Broker: No longer valid to reply with answer.'
|
||||||
else
|
else
|
||||||
dbg 'Broker ERROR: Unexpected ' + xhr.status +
|
dbg 'Broker ERROR: Unexpected ' + xhr.status +
|
||||||
|
|
26
proxy/config.coffee
Normal file
26
proxy/config.coffee
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
class Config
|
||||||
|
brokerUrl: 'snowflake-broker.bamsoftware.com'
|
||||||
|
relayAddr:
|
||||||
|
host: 'snowflake.bamsoftware.com'
|
||||||
|
port: '443'
|
||||||
|
# Original non-wss relay:
|
||||||
|
# host: '192.81.135.242'
|
||||||
|
# port: 9902
|
||||||
|
|
||||||
|
cookieName: "snowflake-allow"
|
||||||
|
|
||||||
|
# Bytes per second. Set to undefined to disable limit.
|
||||||
|
rateLimitBytes: undefined
|
||||||
|
minRateLimit: 10 * 1024
|
||||||
|
rateLimitHistory: 5.0
|
||||||
|
defaultBrokerPollInterval: 5.0 * 1000
|
||||||
|
|
||||||
|
maxNumClients: 1
|
||||||
|
connectionsPerClient: 1
|
||||||
|
|
||||||
|
# TODO: Different ICE servers.
|
||||||
|
pcConfig = {
|
||||||
|
iceServers: [
|
||||||
|
{ urls: ['stun:stun.l.google.com:19302'] }
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,37 +1,9 @@
|
||||||
# General snowflake proxy constants.
|
|
||||||
# For websocket-specific constants, see websocket.coffee.
|
|
||||||
BROKER = 'snowflake-broker.bamsoftware.com'
|
|
||||||
RELAY =
|
|
||||||
host: 'snowflake.bamsoftware.com'
|
|
||||||
port: '443'
|
|
||||||
# Original non-wss relay:
|
|
||||||
# host: '192.81.135.242'
|
|
||||||
# port: 9902
|
|
||||||
COOKIE_NAME = "snowflake-allow"
|
|
||||||
|
|
||||||
# Bytes per second. Set to undefined to disable limit.
|
|
||||||
DEFAULT_RATE_LIMIT = undefined
|
|
||||||
MIN_RATE_LIMIT = 10 * 1024
|
|
||||||
RATE_LIMIT_HISTORY = 5.0
|
|
||||||
DEFAULT_BROKER_POLL_INTERVAL = 5.0 * 1000
|
|
||||||
|
|
||||||
MAX_NUM_CLIENTS = 1
|
|
||||||
CONNECTIONS_PER_CLIENT = 1
|
|
||||||
|
|
||||||
# TODO: Different ICE servers.
|
|
||||||
config = {
|
|
||||||
iceServers: [
|
|
||||||
{ urls: ['stun:stun.l.google.com:19302'] }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
CONFIRMATION_MESSAGE = 'You\'re currently serving a Tor user via Snowflake.'
|
|
||||||
|
|
||||||
query = Query.parse(location)
|
|
||||||
DEBUG = Params.getBool(query, 'debug', false)
|
|
||||||
|
|
||||||
snowflake = null
|
snowflake = null
|
||||||
silenceNotifications = false
|
|
||||||
|
query = Query.parse(location)
|
||||||
|
debug = Params.getBool(query, 'debug', false)
|
||||||
|
silenceNotifications = Params.getBool(query, 'silent', false)
|
||||||
|
|
||||||
# Log to both console and UI if applicable.
|
# Log to both console and UI if applicable.
|
||||||
# Requires that the snowflake and UI objects are hooked up in order to
|
# Requires that the snowflake and UI objects are hooked up in order to
|
||||||
|
@ -40,13 +12,17 @@ log = (msg) ->
|
||||||
console.log 'Snowflake: ' + msg
|
console.log 'Snowflake: ' + msg
|
||||||
snowflake?.ui.log msg
|
snowflake?.ui.log msg
|
||||||
|
|
||||||
dbg = (msg) -> log msg if DEBUG or (snowflake?.ui instanceof DebugUI)
|
dbg = (msg) -> log msg if debug or (snowflake?.ui instanceof DebugUI)
|
||||||
|
|
||||||
|
|
||||||
###
|
###
|
||||||
Entry point.
|
Entry point.
|
||||||
###
|
###
|
||||||
init = () ->
|
init = () ->
|
||||||
|
config = new Config
|
||||||
|
|
||||||
|
if 'off' != query['ratelimit']
|
||||||
|
config.rateLimitBytes = Params.getByteCount(query, 'ratelimit', config.rateLimitBytes)
|
||||||
|
|
||||||
ui = null
|
ui = null
|
||||||
if (document.getElementById('badge') != null)
|
if (document.getElementById('badge') != null)
|
||||||
ui = new BadgeUI()
|
ui = new BadgeUI()
|
||||||
|
@ -57,29 +33,24 @@ init = () ->
|
||||||
else
|
else
|
||||||
ui = new UI()
|
ui = new UI()
|
||||||
|
|
||||||
rateLimitBytes = undefined
|
broker = new Broker config.brokerUrl
|
||||||
if 'off' != query['ratelimit']
|
snowflake = new Snowflake config, ui, broker
|
||||||
rateLimitBytes = Params.getByteCount(query, 'ratelimit', DEFAULT_RATE_LIMIT)
|
|
||||||
|
|
||||||
silenceNotifications = Params.getBool(query, 'silent', false)
|
|
||||||
broker = new Broker BROKER
|
|
||||||
snowflake = new Snowflake broker, ui, rateLimitBytes
|
|
||||||
|
|
||||||
log '== snowflake proxy =='
|
log '== snowflake proxy =='
|
||||||
if Util.snowflakeIsDisabled()
|
if Util.snowflakeIsDisabled(config.cookieName)
|
||||||
# Do not activate the proxy if any number of conditions are true.
|
# Do not activate the proxy if any number of conditions are true.
|
||||||
log 'Currently not active.'
|
log 'Currently not active.'
|
||||||
return
|
return
|
||||||
|
|
||||||
# Otherwise, begin setting up WebRTC and acting as a proxy.
|
# Otherwise, begin setting up WebRTC and acting as a proxy.
|
||||||
dbg 'Contacting Broker at ' + broker.url
|
dbg 'Contacting Broker at ' + broker.url
|
||||||
snowflake.setRelayAddr RELAY
|
snowflake.setRelayAddr config.relayAddr
|
||||||
snowflake.beginWebRTC()
|
snowflake.beginWebRTC()
|
||||||
|
|
||||||
# Notification of closing tab with active proxy.
|
# Notification of closing tab with active proxy.
|
||||||
window.onbeforeunload = ->
|
window.onbeforeunload = ->
|
||||||
if !silenceNotifications && Snowflake.MODE.WEBRTC_READY == snowflake.state
|
if !silenceNotifications && Snowflake.MODE.WEBRTC_READY == snowflake.state
|
||||||
return CONFIRMATION_MESSAGE
|
return Snowflake.MESSAGE.CONFIRMATION
|
||||||
null
|
null
|
||||||
|
|
||||||
window.onunload = ->
|
window.onunload = ->
|
||||||
|
|
|
@ -24,14 +24,14 @@ class ProxyPair
|
||||||
- @relayAddr is the destination relay
|
- @relayAddr is the destination relay
|
||||||
- @rateLimit specifies a rate limit on traffic
|
- @rateLimit specifies a rate limit on traffic
|
||||||
###
|
###
|
||||||
constructor: (@relayAddr, @rateLimit) ->
|
constructor: (@relayAddr, @rateLimit, @pcConfig) ->
|
||||||
@id = Util.genSnowflakeID()
|
@id = Util.genSnowflakeID()
|
||||||
@c2rSchedule = []
|
@c2rSchedule = []
|
||||||
@r2cSchedule = []
|
@r2cSchedule = []
|
||||||
|
|
||||||
# Prepare a WebRTC PeerConnection and await for an SDP offer.
|
# Prepare a WebRTC PeerConnection and await for an SDP offer.
|
||||||
begin: ->
|
begin: ->
|
||||||
@pc = new PeerConnection config, {
|
@pc = new PeerConnection @pcConfig, {
|
||||||
optional: [
|
optional: [
|
||||||
{ DtlsSrtpKeyAgreement: true }
|
{ DtlsSrtpKeyAgreement: true }
|
||||||
{ RtpDataChannels: false }
|
{ RtpDataChannels: false }
|
||||||
|
@ -126,15 +126,13 @@ class ProxyPair
|
||||||
|
|
||||||
# WebRTC --> websocket
|
# WebRTC --> websocket
|
||||||
onClientToRelayMessage: (msg) =>
|
onClientToRelayMessage: (msg) =>
|
||||||
if DEBUG
|
dbg 'WebRTC --> websocket data: ' + msg.data.byteLength + ' bytes'
|
||||||
log 'WebRTC --> websocket data: ' + msg.data.byteLength + ' bytes'
|
|
||||||
@c2rSchedule.push msg.data
|
@c2rSchedule.push msg.data
|
||||||
@flush()
|
@flush()
|
||||||
|
|
||||||
# websocket --> WebRTC
|
# websocket --> WebRTC
|
||||||
onRelayToClientMessage: (event) =>
|
onRelayToClientMessage: (event) =>
|
||||||
if DEBUG
|
dbg 'websocket --> WebRTC data: ' + event.data.byteLength + ' bytes'
|
||||||
log 'websocket --> WebRTC data: ' + event.data.byteLength + ' bytes'
|
|
||||||
@r2cSchedule.push event.data
|
@r2cSchedule.push event.data
|
||||||
@flush()
|
@flush()
|
||||||
|
|
||||||
|
|
|
@ -16,21 +16,26 @@ class Snowflake
|
||||||
retries: 0
|
retries: 0
|
||||||
|
|
||||||
# Janky state machine
|
# Janky state machine
|
||||||
@MODE =
|
@MODE:
|
||||||
INIT: 0
|
INIT: 0
|
||||||
WEBRTC_CONNECTING: 1
|
WEBRTC_CONNECTING: 1
|
||||||
WEBRTC_READY: 2
|
WEBRTC_READY: 2
|
||||||
|
|
||||||
|
@MESSAGE:
|
||||||
|
CONFIRMATION: 'You\'re currently serving a Tor user via Snowflake.'
|
||||||
|
|
||||||
# Prepare the Snowflake with a Broker (to find clients) and optional UI.
|
# Prepare the Snowflake with a Broker (to find clients) and optional UI.
|
||||||
constructor: (@broker, @ui, rateLimitBytes) ->
|
constructor: (@config, @ui, @broker) ->
|
||||||
@state = Snowflake.MODE.INIT
|
@state = Snowflake.MODE.INIT
|
||||||
@proxyPairs = []
|
@proxyPairs = []
|
||||||
|
|
||||||
if undefined == rateLimitBytes
|
if undefined == @config.rateLimitBytes
|
||||||
@rateLimit = new DummyRateLimit()
|
@rateLimit = new DummyRateLimit()
|
||||||
else
|
else
|
||||||
@rateLimit = new BucketRateLimit(rateLimitBytes * RATE_LIMIT_HISTORY,
|
@rateLimit = new BucketRateLimit(
|
||||||
RATE_LIMIT_HISTORY)
|
@config.rateLimitBytes * @config.rateLimitHistory,
|
||||||
|
@config.rateLimitHistory
|
||||||
|
)
|
||||||
@retries = 0
|
@retries = 0
|
||||||
|
|
||||||
# Set the target relay address spec, which is expected to be websocket.
|
# Set the target relay address spec, which is expected to be websocket.
|
||||||
|
@ -45,7 +50,7 @@ class Snowflake
|
||||||
# process. |pollBroker| automatically arranges signalling.
|
# process. |pollBroker| automatically arranges signalling.
|
||||||
beginWebRTC: ->
|
beginWebRTC: ->
|
||||||
@state = Snowflake.MODE.WEBRTC_CONNECTING
|
@state = Snowflake.MODE.WEBRTC_CONNECTING
|
||||||
for i in [1..CONNECTIONS_PER_CLIENT]
|
for i in [1..@config.connectionsPerClient]
|
||||||
@makeProxyPair @relayAddr
|
@makeProxyPair @relayAddr
|
||||||
log 'ProxyPair Slots: ' + @proxyPairs.length
|
log 'ProxyPair Slots: ' + @proxyPairs.length
|
||||||
log 'Snowflake IDs: ' + (@proxyPairs.map (p) -> p.id).join ' | '
|
log 'Snowflake IDs: ' + (@proxyPairs.map (p) -> p.id).join ' | '
|
||||||
|
@ -77,9 +82,9 @@ class Snowflake
|
||||||
recv = @broker.getClientOffer pair.id
|
recv = @broker.getClientOffer pair.id
|
||||||
recv.then (desc) =>
|
recv.then (desc) =>
|
||||||
@receiveOffer pair, desc
|
@receiveOffer pair, desc
|
||||||
countdown('Serving 1 new client.', DEFAULT_BROKER_POLL_INTERVAL / 1000)
|
countdown('Serving 1 new client.', @config.defaultBrokerPollInterval / 1000)
|
||||||
, (err) ->
|
, (err) =>
|
||||||
countdown(err, DEFAULT_BROKER_POLL_INTERVAL / 1000)
|
countdown(err, @config.defaultBrokerPollInterval / 1000)
|
||||||
@retries++
|
@retries++
|
||||||
|
|
||||||
findClients()
|
findClients()
|
||||||
|
@ -111,7 +116,7 @@ class Snowflake
|
||||||
.catch fail
|
.catch fail
|
||||||
|
|
||||||
makeProxyPair: (relay) ->
|
makeProxyPair: (relay) ->
|
||||||
pair = new ProxyPair relay, @rateLimit
|
pair = new ProxyPair relay, @rateLimit, @config.pcConfig
|
||||||
@proxyPairs.push pair
|
@proxyPairs.push pair
|
||||||
pair.onCleanup = (event) =>
|
pair.onCleanup = (event) =>
|
||||||
# Delete from the list of active proxy pairs.
|
# Delete from the list of active proxy pairs.
|
||||||
|
|
|
@ -25,7 +25,7 @@ describe 'Broker', ->
|
||||||
# fake successful request and response from broker.
|
# fake successful request and response from broker.
|
||||||
spyOn(b, '_postRequest').and.callFake ->
|
spyOn(b, '_postRequest').and.callFake ->
|
||||||
b._xhr.readyState = b._xhr.DONE
|
b._xhr.readyState = b._xhr.DONE
|
||||||
b._xhr.status = Broker.STATUS_OK
|
b._xhr.status = Broker.STATUS.OK
|
||||||
b._xhr.responseText = 'fake offer'
|
b._xhr.responseText = 'fake offer'
|
||||||
b._xhr.onreadystatechange()
|
b._xhr.onreadystatechange()
|
||||||
poll = b.getClientOffer()
|
poll = b.getClientOffer()
|
||||||
|
@ -35,7 +35,7 @@ describe 'Broker', ->
|
||||||
expect(desc).toEqual 'fake offer'
|
expect(desc).toEqual 'fake offer'
|
||||||
done()
|
done()
|
||||||
.catch ->
|
.catch ->
|
||||||
fail 'should not reject on Broker.STATUS_OK'
|
fail 'should not reject on Broker.STATUS.OK'
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'rejects if the broker timed-out', (done) ->
|
it 'rejects if the broker timed-out', (done) ->
|
||||||
|
@ -43,16 +43,16 @@ describe 'Broker', ->
|
||||||
# fake timed-out request from broker
|
# fake timed-out request from broker
|
||||||
spyOn(b, '_postRequest').and.callFake ->
|
spyOn(b, '_postRequest').and.callFake ->
|
||||||
b._xhr.readyState = b._xhr.DONE
|
b._xhr.readyState = b._xhr.DONE
|
||||||
b._xhr.status = Broker.STATUS_GATEWAY_TIMEOUT
|
b._xhr.status = Broker.STATUS.GATEWAY_TIMEOUT
|
||||||
b._xhr.onreadystatechange()
|
b._xhr.onreadystatechange()
|
||||||
poll = b.getClientOffer()
|
poll = b.getClientOffer()
|
||||||
expect(poll).not.toBeNull()
|
expect(poll).not.toBeNull()
|
||||||
expect(b._postRequest).toHaveBeenCalled()
|
expect(b._postRequest).toHaveBeenCalled()
|
||||||
poll.then (desc) ->
|
poll.then (desc) ->
|
||||||
fail 'should not fulfill on GATEWAY_TIMEOUT'
|
fail 'should not fulfill on Broker.STATUS.GATEWAY_TIMEOUT'
|
||||||
done()
|
done()
|
||||||
, (err) ->
|
, (err) ->
|
||||||
expect(err).toBe Broker.MESSAGE_TIMEOUT
|
expect(err).toBe Broker.MESSAGE.TIMEOUT
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'rejects on any other status', (done) ->
|
it 'rejects on any other status', (done) ->
|
||||||
|
@ -69,7 +69,7 @@ describe 'Broker', ->
|
||||||
fail 'should not fulfill on non-OK status'
|
fail 'should not fulfill on non-OK status'
|
||||||
done()
|
done()
|
||||||
, (err) ->
|
, (err) ->
|
||||||
expect(err).toBe Broker.MESSAGE_UNEXPECTED
|
expect(err).toBe Broker.MESSAGE.UNEXPECTED
|
||||||
expect(b._xhr.status).toBe 1337
|
expect(b._xhr.status).toBe 1337
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
|
28
proxy/spec/init.spec.coffee
Normal file
28
proxy/spec/init.spec.coffee
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
# Fake snowflake to interact with
|
||||||
|
snowflake =
|
||||||
|
ui: new UI
|
||||||
|
broker:
|
||||||
|
sendAnswer: ->
|
||||||
|
state: Snowflake.MODE.INIT
|
||||||
|
|
||||||
|
describe 'Init', ->
|
||||||
|
|
||||||
|
it 'gives a dialog when closing, only while active', ->
|
||||||
|
silenceNotifications = false
|
||||||
|
snowflake.state = Snowflake.MODE.WEBRTC_READY
|
||||||
|
msg = window.onbeforeunload()
|
||||||
|
expect(snowflake.state).toBe Snowflake.MODE.WEBRTC_READY
|
||||||
|
expect(msg).toBe Snowflake.MESSAGE.CONFIRMATION
|
||||||
|
|
||||||
|
snowflake.state = Snowflake.MODE.INIT
|
||||||
|
msg = window.onbeforeunload()
|
||||||
|
expect(snowflake.state).toBe Snowflake.MODE.INIT
|
||||||
|
expect(msg).toBe null
|
||||||
|
|
||||||
|
it 'does not give a dialog when silent flag is on', ->
|
||||||
|
silenceNotifications = true
|
||||||
|
snowflake.state = Snowflake.MODE.WEBRTC_READY
|
||||||
|
msg = window.onbeforeunload()
|
||||||
|
expect(snowflake.state).toBe Snowflake.MODE.WEBRTC_READY
|
||||||
|
expect(msg).toBe null
|
|
@ -24,10 +24,11 @@ arrayMatching = (sample) -> {
|
||||||
|
|
||||||
describe 'ProxyPair', ->
|
describe 'ProxyPair', ->
|
||||||
fakeRelay = Parse.address '0.0.0.0:12345'
|
fakeRelay = Parse.address '0.0.0.0:12345'
|
||||||
rateLimit = new DummyRateLimit()
|
rateLimit = new DummyRateLimit
|
||||||
|
config = new Config
|
||||||
destination = []
|
destination = []
|
||||||
# Using the mock PeerConnection definition from spec/snowflake.spec.coffee.
|
# Using the mock PeerConnection definition from spec/snowflake.spec.coffee.
|
||||||
pp = new ProxyPair(fakeRelay, rateLimit)
|
pp = new ProxyPair(fakeRelay, rateLimit, config.pcConfig)
|
||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
pp.begin()
|
pp.begin()
|
||||||
|
|
|
@ -15,40 +15,38 @@ class WebSocket
|
||||||
constructor: ->
|
constructor: ->
|
||||||
@bufferedAmount = 0
|
@bufferedAmount = 0
|
||||||
send: (data) ->
|
send: (data) ->
|
||||||
|
|
||||||
log = ->
|
log = ->
|
||||||
fakeUI = new UI()
|
|
||||||
|
config = new Config
|
||||||
|
ui = new UI
|
||||||
|
|
||||||
class FakeBroker
|
class FakeBroker
|
||||||
getClientOffer: -> new Promise((F,R) -> {})
|
getClientOffer: -> new Promise((F,R) -> {})
|
||||||
# Fake snowflake to interact with
|
|
||||||
snowflake =
|
|
||||||
ui: fakeUI
|
|
||||||
broker:
|
|
||||||
sendAnswer: ->
|
|
||||||
state: Snowflake.MODE.INIT
|
|
||||||
|
|
||||||
describe 'Snowflake', ->
|
describe 'Snowflake', ->
|
||||||
|
|
||||||
it 'constructs correctly', ->
|
it 'constructs correctly', ->
|
||||||
s = new Snowflake({ fake: 'broker' }, fakeUI)
|
s = new Snowflake(config, ui, { fake: 'broker' })
|
||||||
expect(s.rateLimit).not.toBeNull()
|
expect(s.rateLimit).not.toBeNull()
|
||||||
expect(s.broker).toEqual { fake: 'broker' }
|
expect(s.broker).toEqual { fake: 'broker' }
|
||||||
expect(s.ui).not.toBeNull()
|
expect(s.ui).not.toBeNull()
|
||||||
expect(s.retries).toBe 0
|
expect(s.retries).toBe 0
|
||||||
|
|
||||||
it 'sets relay address correctly', ->
|
it 'sets relay address correctly', ->
|
||||||
s = new Snowflake(null, fakeUI)
|
s = new Snowflake(config, ui, null)
|
||||||
s.setRelayAddr 'foo'
|
s.setRelayAddr 'foo'
|
||||||
expect(s.relayAddr).toEqual 'foo'
|
expect(s.relayAddr).toEqual 'foo'
|
||||||
|
|
||||||
it 'initalizes WebRTC connection', ->
|
it 'initalizes WebRTC connection', ->
|
||||||
s = new Snowflake(new FakeBroker(), fakeUI)
|
s = new Snowflake(config, ui, new FakeBroker())
|
||||||
spyOn(s.broker, 'getClientOffer').and.callThrough()
|
spyOn(s.broker, 'getClientOffer').and.callThrough()
|
||||||
s.beginWebRTC()
|
s.beginWebRTC()
|
||||||
expect(s.retries).toBe 1
|
expect(s.retries).toBe 1
|
||||||
expect(s.broker.getClientOffer).toHaveBeenCalled()
|
expect(s.broker.getClientOffer).toHaveBeenCalled()
|
||||||
|
|
||||||
it 'receives SDP offer and sends answer', ->
|
it 'receives SDP offer and sends answer', ->
|
||||||
s = new Snowflake(new FakeBroker(), fakeUI)
|
s = new Snowflake(config, ui, new FakeBroker())
|
||||||
pair = { receiveWebRTCOffer: -> }
|
pair = { receiveWebRTCOffer: -> }
|
||||||
spyOn(pair, 'receiveWebRTCOffer').and.returnValue true
|
spyOn(pair, 'receiveWebRTCOffer').and.returnValue true
|
||||||
spyOn(s, 'sendAnswer')
|
spyOn(s, 'sendAnswer')
|
||||||
|
@ -56,7 +54,7 @@ describe 'Snowflake', ->
|
||||||
expect(s.sendAnswer).toHaveBeenCalled()
|
expect(s.sendAnswer).toHaveBeenCalled()
|
||||||
|
|
||||||
it 'does not send answer when receiving invalid offer', ->
|
it 'does not send answer when receiving invalid offer', ->
|
||||||
s = new Snowflake(new FakeBroker(), fakeUI)
|
s = new Snowflake(config, ui, new FakeBroker())
|
||||||
pair = { receiveWebRTCOffer: -> }
|
pair = { receiveWebRTCOffer: -> }
|
||||||
spyOn(pair, 'receiveWebRTCOffer').and.returnValue false
|
spyOn(pair, 'receiveWebRTCOffer').and.returnValue false
|
||||||
spyOn(s, 'sendAnswer')
|
spyOn(s, 'sendAnswer')
|
||||||
|
@ -64,25 +62,6 @@ describe 'Snowflake', ->
|
||||||
expect(s.sendAnswer).not.toHaveBeenCalled()
|
expect(s.sendAnswer).not.toHaveBeenCalled()
|
||||||
|
|
||||||
it 'can make a proxypair', ->
|
it 'can make a proxypair', ->
|
||||||
s = new Snowflake(new FakeBroker(), fakeUI)
|
s = new Snowflake(config, ui, new FakeBroker())
|
||||||
s.makeProxyPair()
|
s.makeProxyPair()
|
||||||
expect(s.proxyPairs.length).toBe 1
|
expect(s.proxyPairs.length).toBe 1
|
||||||
|
|
||||||
it 'gives a dialog when closing, only while active', ->
|
|
||||||
silenceNotifications = false
|
|
||||||
snowflake.state = Snowflake.MODE.WEBRTC_READY
|
|
||||||
msg = window.onbeforeunload()
|
|
||||||
expect(snowflake.state).toBe Snowflake.MODE.WEBRTC_READY
|
|
||||||
expect(msg).toBe CONFIRMATION_MESSAGE
|
|
||||||
|
|
||||||
snowflake.state = Snowflake.MODE.INIT
|
|
||||||
msg = window.onbeforeunload()
|
|
||||||
expect(snowflake.state).toBe Snowflake.MODE.INIT
|
|
||||||
expect(msg).toBe null
|
|
||||||
|
|
||||||
it 'does not give a dialog when silent flag is on', ->
|
|
||||||
silenceNotifications = true
|
|
||||||
snowflake.state = Snowflake.MODE.WEBRTC_READY
|
|
||||||
msg = window.onbeforeunload()
|
|
||||||
expect(snowflake.state).toBe Snowflake.MODE.WEBRTC_READY
|
|
||||||
expect(msg).toBe null
|
|
||||||
|
|
|
@ -22,10 +22,10 @@ class Util
|
||||||
@genSnowflakeID: ->
|
@genSnowflakeID: ->
|
||||||
Math.random().toString(36).substring(2)
|
Math.random().toString(36).substring(2)
|
||||||
|
|
||||||
@snowflakeIsDisabled = ->
|
@snowflakeIsDisabled = (cookieName) ->
|
||||||
cookies = Parse.cookie document.cookie
|
cookies = Parse.cookie document.cookie
|
||||||
# Do nothing if snowflake has not been opted in by user.
|
# Do nothing if snowflake has not been opted in by user.
|
||||||
if cookies[COOKIE_NAME] != '1'
|
if cookies[cookieName] != '1'
|
||||||
log 'Not opted-in. Please click the badge to change options.'
|
log 'Not opted-in. Please click the badge to change options.'
|
||||||
return true
|
return true
|
||||||
# Also do nothing if running in Tor Browser.
|
# Also do nothing if running in Tor Browser.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue