1 //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef ProtocolParser_h__
7 #define ProtocolParser_h__
8 
9 #include "HashStore.h"
10 #include "chromium/safebrowsing.pb.h"
11 
12 namespace mozilla {
13 namespace safebrowsing {
14 
15 /**
16  * Abstract base class for parsing update data in multiple formats.
17  */
18 class ProtocolParser {
19  public:
20   struct ForwardedUpdate {
21     nsCString table;
22     nsCString url;
23   };
24 
25   ProtocolParser();
26   virtual ~ProtocolParser();
27 
Status()28   nsresult Status() const { return mUpdateStatus; }
29 
30 #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
GetRawTableUpdates()31   virtual nsCString GetRawTableUpdates() const { return mPending; }
32 #endif
33 
34   virtual void SetCurrentTable(const nsACString& aTable) = 0;
35 
SetRequestedTables(const nsTArray<nsCString> & aRequestTables)36   void SetRequestedTables(const nsTArray<nsCString>& aRequestTables) {
37     mRequestedTables = aRequestTables.Clone();
38   }
39 
40   nsresult Begin(const nsACString& aTable,
41                  const nsTArray<nsCString>& aUpdateTables);
42   virtual nsresult AppendStream(const nsACString& aData) = 0;
43 
UpdateWaitSec()44   uint32_t UpdateWaitSec() { return mUpdateWaitSec; }
45 
46   // Notify that the inbound data is ready for parsing if progressive
47   // parsing is not supported, for example in V4.
48   virtual void End() = 0;
49 
50   RefPtr<TableUpdate> GetTableUpdate(const nsACString& aTable);
ForgetTableUpdates()51   void ForgetTableUpdates() { mTableUpdates.Clear(); }
GetTableUpdates()52   const TableUpdateArray& GetTableUpdates() { return mTableUpdates; }
53 
54   // These are only meaningful to V2. Since they were originally public,
55   // moving them to ProtocolParserV2 requires a dymamic cast in the call
56   // sites. As a result, we will leave them until we remove support
57   // for V2 entirely..
Forwards()58   virtual const nsTArray<ForwardedUpdate>& Forwards() const {
59     return mForwards;
60   }
ResetRequested()61   bool ResetRequested() const { return !mTablesToReset.IsEmpty(); }
TablesToReset()62   const nsTArray<nsCString>& TablesToReset() const { return mTablesToReset; }
63 
64  protected:
65   virtual RefPtr<TableUpdate> CreateTableUpdate(
66       const nsACString& aTableName) const = 0;
67 
68   nsCString mPending;
69   nsresult mUpdateStatus;
70 
71   // Keep track of updates to apply before passing them to the DBServiceWorkers.
72   TableUpdateArray mTableUpdates;
73 
74   nsTArray<ForwardedUpdate> mForwards;
75 
76   // The table names that were requested from the client.
77   nsTArray<nsCString> mRequestedTables;
78 
79   // The table names that failed to update and need to be reset.
80   nsTArray<nsCString> mTablesToReset;
81 
82   // How long we should wait until the next update.
83   uint32_t mUpdateWaitSec;
84 };
85 
86 /**
87  * Helpers to parse the "shavar", "digest256" and "simple" list formats.
88  */
89 class ProtocolParserV2 final : public ProtocolParser {
90  public:
91   ProtocolParserV2();
92   virtual ~ProtocolParserV2();
93 
94   virtual void SetCurrentTable(const nsACString& aTable) override;
95   virtual nsresult AppendStream(const nsACString& aData) override;
96   virtual void End() override;
97 
98   // Update information.
Forwards()99   virtual const nsTArray<ForwardedUpdate>& Forwards() const override {
100     return mForwards;
101   }
102 
103 #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
104   // Unfortunately we have to override to return mRawUpdate which
105   // will not be modified during the parsing, unlike mPending.
GetRawTableUpdates()106   virtual nsCString GetRawTableUpdates() const override { return mRawUpdate; }
107 #endif
108 
109  private:
110   virtual RefPtr<TableUpdate> CreateTableUpdate(
111       const nsACString& aTableName) const override;
112 
113   nsresult ProcessControl(bool* aDone);
114   nsresult ProcessExpirations(const nsCString& aLine);
115   nsresult ProcessChunkControl(const nsCString& aLine);
116   nsresult ProcessForward(const nsCString& aLine);
117   nsresult AddForward(const nsACString& aUrl);
118   nsresult ProcessChunk(bool* done);
119   // Remove this, it's only used for testing
120   nsresult ProcessPlaintextChunk(const nsACString& aChunk);
121   nsresult ProcessShaChunk(const nsACString& aChunk);
122   nsresult ProcessHostAdd(const Prefix& aDomain, uint8_t aNumEntries,
123                           const nsACString& aChunk, uint32_t* aStart);
124   nsresult ProcessHostSub(const Prefix& aDomain, uint8_t aNumEntries,
125                           const nsACString& aChunk, uint32_t* aStart);
126   nsresult ProcessHostAddComplete(uint8_t aNumEntries, const nsACString& aChunk,
127                                   uint32_t* aStart);
128   nsresult ProcessHostSubComplete(uint8_t numEntries, const nsACString& aChunk,
129                                   uint32_t* start);
130   // Digest chunks are very similar to shavar chunks, except digest chunks
131   // always contain the full hash, so there is no need for chunk data to
132   // contain prefix sizes.
133   nsresult ProcessDigestChunk(const nsACString& aChunk);
134   nsresult ProcessDigestAdd(const nsACString& aChunk);
135   nsresult ProcessDigestSub(const nsACString& aChunk);
136   bool NextLine(nsACString& aLine);
137 
138   enum ParserState { PROTOCOL_STATE_CONTROL, PROTOCOL_STATE_CHUNK };
139   ParserState mState;
140 
141   enum ChunkType {
142     // Types for shavar tables.
143     CHUNK_ADD,
144     CHUNK_SUB,
145     // Types for digest256 tables. digest256 tables differ in format from
146     // shavar tables since they only contain complete hashes.
147     CHUNK_ADD_DIGEST,
148     CHUNK_SUB_DIGEST
149   };
150 
151   struct ChunkState {
152     ChunkType type;
153     uint32_t num;
154     uint32_t hashSize;
155     uint32_t length;
ClearChunkState156     void Clear() {
157       num = 0;
158       hashSize = 0;
159       length = 0;
160     }
161   };
162   ChunkState mChunkState;
163 
164   // Updates to apply to the current table being parsed.
165   RefPtr<TableUpdateV2> mTableUpdate;
166 
167 #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
168   nsCString mRawUpdate;  // Keep a copy of mPending before it's processed.
169 #endif
170 };
171 
172 // Helpers to parse the "proto" list format.
173 class ProtocolParserProtobuf final : public ProtocolParser {
174  public:
175   typedef FetchThreatListUpdatesResponse_ListUpdateResponse ListUpdateResponse;
176   typedef google::protobuf::RepeatedPtrField<ThreatEntrySet> ThreatEntrySetList;
177 
178  public:
179   ProtocolParserProtobuf();
180 
181   virtual void SetCurrentTable(const nsACString& aTable) override;
182   virtual nsresult AppendStream(const nsACString& aData) override;
183   virtual void End() override;
184 
185  private:
186   virtual ~ProtocolParserProtobuf();
187 
188   virtual RefPtr<TableUpdate> CreateTableUpdate(
189       const nsACString& aTableName) const override;
190 
191   // For parsing update info.
192   nsresult ProcessOneResponse(const ListUpdateResponse& aResponse,
193                               nsACString& aListName);
194 
195   nsresult ProcessAdditionOrRemoval(TableUpdateV4& aTableUpdate,
196                                     const ThreatEntrySetList& aUpdate,
197                                     bool aIsAddition);
198 
199   nsresult ProcessRawAddition(TableUpdateV4& aTableUpdate,
200                               const ThreatEntrySet& aAddition);
201 
202   nsresult ProcessRawRemoval(TableUpdateV4& aTableUpdate,
203                              const ThreatEntrySet& aRemoval);
204 
205   nsresult ProcessEncodedAddition(TableUpdateV4& aTableUpdate,
206                                   const ThreatEntrySet& aAddition);
207 
208   nsresult ProcessEncodedRemoval(TableUpdateV4& aTableUpdate,
209                                  const ThreatEntrySet& aRemoval);
210 };
211 
212 }  // namespace safebrowsing
213 }  // namespace mozilla
214 
215 #endif
216