@@ -82,6 +82,11 @@ class WebPusher:
8282
8383 """
8484 subscription_info = {}
85+ valid_encodings = [
86+ # "aesgcm128", # this is draft-0, but DO NOT USE.
87+ "aesgcm" , # draft-httpbis-encryption-encoding-01
88+ "aes128gcm" # draft-httpbis-encryption-encoding-04
89+ ]
8590
8691 def __init__ (self , subscription_info ):
8792 """Initialize using the info provided by the client PushSubscription
@@ -113,16 +118,28 @@ def _repad(self, data):
113118 """Add base64 padding to the end of a string, if required"""
114119 return data + b"====" [:len (data ) % 4 ]
115120
116- def encode (self , data ):
121+ def encode (self , data , content_encoding = "aesgcm" ):
117122 """Encrypt the data.
118123
119124 :param data: A serialized block of byte data (String, JSON, bit array,
120125 etc.) Make sure that whatever you send, your client knows how
121126 to understand it.
127+ :type data: str
128+ :param content_encoding: The content_encoding type to use to encrypt
129+ the data. Defaults to draft-01 "aesgcm". Latest draft-04 is
130+ "aes128gcm", however not all clients may be able to use this
131+ format.
132+ :type content_encoding: enum("aesgcm", "aes128gcm")
122133
123134 """
124135 # Salt is a random 16 byte array.
125- salt = os .urandom (16 )
136+ salt = None
137+ if content_encoding not in self .valid_encodings :
138+ raise WebPushException ("Invalid content encoding specified. "
139+ "Select from " +
140+ json .dumps (self .valid_encodings ))
141+ if (content_encoding == "aesgcm" ):
142+ salt = os .urandom (16 )
126143 # The server key is an ephemeral ECDH key used only for this
127144 # transaction
128145 server_key = pyelliptic .ECC (curve = "prime256v1" )
@@ -133,26 +150,31 @@ def encode(self, data):
133150 if isinstance (data , six .string_types ):
134151 data = bytes (data .encode ('utf8' ))
135152
153+ key_id = server_key_id .decode ('utf8' )
136154 # http_ece requires that these both be set BEFORE encrypt or
137155 # decrypt is called if you specify the key as "dh".
138- http_ece .keys [server_key_id ] = server_key
139- http_ece .labels [server_key_id ] = "P-256"
156+ http_ece .keys [key_id ] = server_key
157+ http_ece .labels [key_id ] = "P-256"
140158
141159 encrypted = http_ece .encrypt (
142160 data ,
143161 salt = salt ,
144- keyid = server_key_id ,
162+ keyid = key_id ,
145163 dh = self .receiver_key ,
146- authSecret = self .auth_key )
164+ authSecret = self .auth_key ,
165+ version = content_encoding )
147166
148- return CaseInsensitiveDict ({
167+ reply = CaseInsensitiveDict ({
149168 'crypto_key' : base64 .urlsafe_b64encode (
150169 server_key .get_pubkey ()).strip (b'=' ),
151- 'salt' : base64 .urlsafe_b64encode (salt ).strip (b'=' ),
152170 'body' : encrypted ,
153171 })
172+ if salt :
173+ reply ['salt' ] = base64 .urlsafe_b64encode (salt ).strip (b'=' )
174+ return reply
154175
155- def send (self , data = None , headers = None , ttl = 0 , gcm_key = None , reg_id = None ):
176+ def send (self , data = None , headers = None , ttl = 0 , gcm_key = None , reg_id = None ,
177+ content_encoding = "aesgcm" ):
156178 """Encode and send the data to the Push Service.
157179
158180 :param data: A serialized block of data (see encode() ).
0 commit comments