adguard_flm/manager/mod.rs
1//! Filter list manager library main facade interface.
2pub mod filter_list_manager_impl;
3pub(crate) mod filter_lists_builder;
4pub mod managers;
5pub mod models;
6mod update_filters_action;
7
8use crate::manager::models::active_rules_info::ActiveRulesInfo;
9use crate::manager::models::configuration::request_proxy_mode::RequestProxyMode;
10use crate::manager::models::configuration::Locale;
11use crate::manager::models::disabled_rules_raw::DisabledRulesRaw;
12use crate::manager::models::filter_group::FilterGroup;
13use crate::manager::models::filter_list_rules::FilterListRules;
14use crate::manager::models::filter_list_rules_raw::FilterListRulesRaw;
15use crate::manager::models::filter_tag::FilterTag;
16use crate::manager::models::rules_count_by_filter::RulesCountByFilter;
17use crate::manager::models::{PullMetadataResult, UpdateResult};
18use crate::{ActiveRulesInfoRaw, FLMResult, StoredFilterMetadata};
19use models::configuration::Configuration;
20use models::filter_list_metadata::FilterListMetadata;
21use models::filter_list_metadata_with_body::FilterListMetadataWithBody;
22use models::full_filter_list::FullFilterList;
23use models::FilterId;
24use std::path::Path;
25
26/// FilterListManager is the interface of a filter list manager.
27pub trait FilterListManager {
28 /// In the constructor, the object is configured and initialized depending on the passed configuration.
29 /// *NOTE:* You must create its own manager for different filter lists types.
30 ///
31 /// * `configuration` - Configuration object for this manager
32 fn new(configuration: Configuration) -> FLMResult<Box<Self>>;
33
34 /// Installs a custom filter list
35 ///
36 /// * `download_url` - Remote server or a `file://` URL. Can be an
37 /// *empty string*. In that case filter will be local. (e.g. won't be
38 /// updated).
39 /// * `is_trusted` - Does this filter considered trusted.
40 /// * `title` - Override title. If passed, title from metadata will be
41 /// ignored.
42 /// * `description` - Override description. If passed, description from
43 /// metadata will be ignored.
44 ///
45 /// Returns the inserted filter list.
46 fn install_custom_filter_list(
47 &self,
48 download_url: String,
49 is_trusted: bool,
50 title: Option<String>,
51 description: Option<String>,
52 ) -> FLMResult<FullFilterList>;
53
54 /// Fetches filter list by url and returns its raw metadata.
55 ///
56 /// * `url` - Remote server or a `file://` URL.
57 ///
58 /// Returns filter list metadata.
59 fn fetch_filter_list_metadata(&self, url: String) -> FLMResult<FilterListMetadata>;
60
61 /// Fetches filter list by url and returns its raw metadata and body.
62 ///
63 /// * `url` - Remote server or a `file://` URL.
64 ///
65 /// Returns filter list metadata and body.
66 fn fetch_filter_list_metadata_with_body(
67 &self,
68 url: String,
69 ) -> FLMResult<FilterListMetadataWithBody>;
70
71 /// Toggles filter lists, using their `filter_id`.
72 ///
73 /// * `ids` - List of [`FilterId`].
74 /// * `is_enabled` - Does this filter list enabled.
75 ///
76 /// Returns SQL's affected rows count.
77 fn enable_filter_lists(&self, ids: Vec<FilterId>, is_enabled: bool) -> FLMResult<usize>;
78
79 /// Toggles `is_installed` property of filter list.
80 ///
81 /// * `ids` - List of [`FilterId`].
82 /// * `is_installed` - new flag value.
83 ///
84 /// Returns SQL's affected rows count.
85 fn install_filter_lists(&self, ids: Vec<FilterId>, is_installed: bool) -> FLMResult<usize>;
86
87 /// Deletes custom filter lists, using their filter_id.
88 ///
89 /// * `ids` - List of [`FilterId`].
90 ///
91 /// Returns SQL's affected rows count.
92 fn delete_custom_filter_lists(&self, ids: Vec<FilterId>) -> FLMResult<usize>;
93
94 /// Gets all tags from DB.
95 fn get_all_tags(&self) -> FLMResult<Vec<FilterTag>>;
96
97 /// Gets all groups from DB.
98 fn get_all_groups(&self) -> FLMResult<Vec<FilterGroup>>;
99
100 /// Returns all filter data including its rules by [`FilterId`]. Fields [`title`, `description`] will be
101 /// localised with selected [`Locale`].
102 fn get_full_filter_list_by_id(&self, filter_id: FilterId) -> FLMResult<Option<FullFilterList>>;
103
104 /// Returns all stored filters metadata. This is the lightweight counterpart of `.get_full_filter_lists()`
105 /// Fields [`title`, `description`] will be localised with selected [`Locale`].
106 fn get_stored_filters_metadata(&self) -> FLMResult<Vec<StoredFilterMetadata>>;
107
108 /// Returns stored filter metadata by [`FilterId`]. This is the lightweight counterpart of `.get_full_filter_list_by_id(filter_id)`
109 /// Fields [`title`, `description`] will be localised with selected [`Locale`].
110 fn get_stored_filter_metadata_by_id(
111 &self,
112 filter_id: FilterId,
113 ) -> FLMResult<Option<StoredFilterMetadata>>;
114
115 /// Save custom filter list rules. Note that `filter.time_updated` will be updated too.
116 ///
117 /// # Failure
118 ///
119 /// Returns [`Err`] if the specified [`FilterId`] is not found in the
120 /// database, or it is not from custom filter.
121 fn save_custom_filter_rules(&self, rules: FilterListRules) -> FLMResult<()>;
122
123 /// Saves a set of disabled filters for a specific [`FilterId`]
124 ///
125 /// # Failure
126 ///
127 /// Fails if rules_list entity does not exist for passed `filter_id`.
128 /// This because if you want to keep disabled filters, you should already
129 /// have a `rules_list` entity.
130 fn save_disabled_rules(
131 &self,
132 filter_id: FilterId,
133 disabled_rules: Vec<String>,
134 ) -> FLMResult<()>;
135
136 /// Filters updates is conducted in the multiple steps:
137 /// - Search for filters ready for update.
138 /// - Fetch them.
139 /// - Save `last_download_time`, and update metadata.
140 /// - Collect updated filters.
141 ///
142 /// # Internal checks
143 ///
144 /// This method conducts the following checks while updating filters:
145 /// - Filter expiration (or `ignore_filters_expiration` flag)
146 /// - Content equality via checksum comparison (not Checksum metadata field) (`ignore_filters_expiration` flag disables this check)
147 /// - Filter status (is_enabled) or `ignore_filters_status` flag
148 /// - Local urls without `download_url` won't be updated
149 /// - For index filters, versions are checked through `Version` metadata field checking up against the latest version from the index file
150 /// - Also `loose_timeout` can limit count of updated filters if non-zero
151 ///
152 /// # Parameters
153 ///
154 /// * `ignore_filters_expiration` - Does not rely on filter's expire
155 /// information, also ignores content equality via checksum comparison.
156 /// * `loose_timeout` - Not a strict timeout, checked after processing each
157 /// filter. If the total time exceeds this value, filters processing will
158 /// stop, and the number of unprocessed filters will be set in result
159 /// value. Pass 0 to disable timeout.
160 /// * `ignore_filters_status` - Include disabled filters
161 ///
162 /// Returns [`UpdateResult`] with update information.
163 ///
164 /// # Failure
165 ///
166 /// Returns [`None`] if DB is empty.
167 ///
168 /// Returns [`Err`] if you can not get records from db, or common error
169 /// encountered.
170 ///
171 /// Note: should be used no more than once an hour.
172 fn update_filters(
173 &self,
174 ignore_filters_expiration: bool,
175 loose_timeout: i32,
176 ignore_filters_status: bool,
177 ) -> FLMResult<Option<UpdateResult>>;
178
179 /// This method works almost the same as [`Self::update_filters`].
180 /// But also, you MUST pass the list of [`FilterId`].
181 /// Empty list will cause an empty result [`Ok(UpdateResult.updated_list == 0)`] if database exists.
182 /// This returns [`Ok(None)`] if db is empty
183 fn update_filters_by_ids(
184 &self,
185 ids: Vec<FilterId>,
186 ignore_filters_expiration: bool,
187 loose_timeout: i32,
188 ignore_filters_status: bool,
189 ) -> FLMResult<Option<UpdateResult>>;
190
191 /// Tries to update passed list of [`FilterId`].
192 /// The logic is the same as in the filter update method [`FilterListManager::update_filters`]
193 /// with exceptions:
194 /// * This returns [`None`] if DB result set is empty.
195 /// * This always ignores filters `expires` and `is_enabled` parameters.
196 ///
197 /// * `ids` - List of [`FilterId`].
198 /// * `loose_timeout` - See [`FilterListManager::update_filters`]
199 /// `loose_timeout` parameter for explanation.
200 ///
201 /// Note: should be used once an hour or less.
202 fn force_update_filters_by_ids(
203 &self,
204 ids: Vec<FilterId>,
205 loose_timeout: i32,
206 ) -> FLMResult<Option<UpdateResult>>;
207
208 /// Tries to change [`Locale`] in configuration.
209 /// Will search `suggested_locale` in database. If it cannot find exact
210 /// locale, like `en_GB`, it will try to find language code - `en`. Locales
211 /// with "-", like `en-GB`, will be normalised to internal format - `en_GB`.
212 ///
213 /// Returns a [`bool`] indicating the success of changing the locale.
214 /// If the locale is not found, `false` will be returned.
215 fn change_locale(&mut self, suggested_locale: Locale) -> FLMResult<bool>;
216
217 /// The method is used for creating a database and downloading filters.
218 /// If the database exists, it attempts to bring it to a state compatible
219 /// with the current indexes. Also, migrations update will be processed in this method, too.
220 /// Additionally, the method checks the downloaded indexes for consistency.
221 ///
222 /// This method follows the algorithm below:
223 ///
224 /// 1. Downloads the filters index (registry).
225 /// 2. Checks the index consistency.
226 /// a. Take filters from the index.
227 /// b. For each filter check that `filter.group_id` > 0 and the group
228 /// is present in the index.
229 /// c. For each filter check that tag is present in the index.
230 /// d. `filter.name` (title) is not empty.
231 /// e. `filter.download_url` must be unique.
232 /// f. Everything else is not a critical issue.
233 /// 3. Opens the database with `O_CREAT`.
234 /// a. Check that the database is empty (by the presence of the `filter`
235 /// table).
236 /// b. If empty, pour the schema and save the data from the indexes and
237 /// finish the exercise.
238 /// c. Otherwise, go to the next step.
239 /// 4. Select all filters from the database, then iterate on every filter.
240 /// When comparing filters from the index and the database, we rely on
241 /// the filter.id.
242 /// a. If it is a custom filter - (`group_id` < 1) -> continue.
243 /// b. Do not work with `filter_id` < 1 (reserved filters) -> continue.
244 /// c. If a filter is enabled and is not in the new index -> move it to
245 /// the custom group and change its ID.
246 /// d. If the filter is disabled or not installed -> delete it.
247 /// e. Take the filter and replace the following fields with values from
248 /// the index:
249 /// * `display_number`
250 /// * `title`
251 /// * `description`
252 /// * `homepage`
253 /// * `expires`
254 /// * `download_url`
255 /// * `subscription_url`
256 /// * `last_update_time`
257 /// f. Mark the filter in the index as processed.
258 /// 5. Remove old groups/tags/locales.
259 /// 6. Fill in new groups/tags/locales.
260 /// 7. Fill in our updated filters along with the raw filters from the
261 /// index.
262 ///
263 /// Note: should be used no more than once a week.
264 ///
265 /// # Returns
266 ///
267 /// [`PullMetadataResult`] - the result of index metadata update
268 fn pull_metadata(&self) -> FLMResult<PullMetadataResult>;
269
270 /// Updates custom filter data.
271 ///
272 /// * `filter_id` - Custom filter id.
273 /// * `title` - New `title` for filter.
274 /// * `is_trusted` - New `is_trusted` status for filter.
275 ///
276 /// # Failure
277 ///
278 /// Fails if manager couldn't find a filter by `filter_id` or if `filter_id`
279 /// is not from a custom filter. Fails if title is empty.
280 fn update_custom_filter_metadata(
281 &self,
282 filter_id: FilterId,
283 title: String,
284 is_trusted: bool,
285 ) -> FLMResult<bool>;
286
287 /// Gets absolute path for current database.
288 fn get_database_path(&self) -> FLMResult<String>;
289
290 /// The method “raises” the state of the database to the working state.
291 ///
292 /// **If the database doesn't exist:**
293 /// - Creates database
294 /// - Rolls up the schema
295 /// - Rolls migrations
296 /// - Performs bootstrap.
297 ///
298 /// **If the database is an empty file:**
299 /// - Rolls the schema
300 /// - Rolls migrations
301 /// - Performs bootstrap.
302 ///
303 ///... and so on.
304 fn lift_up_database(&self) -> FLMResult<()>;
305
306 /// Gets version of current database scheme.
307 ///
308 /// # Special case
309 ///
310 /// Can return [`None`] if database file exists, but metadata table does not
311 /// exist.
312 fn get_database_version(&self) -> FLMResult<Option<i32>>;
313
314 /// Installs custom filter from string
315 ///
316 /// * `download_url` - Download url for filter. String will be placed
317 /// *as is*. See [FilterListManager::install_custom_filter_list] for the
318 /// format.
319 /// * `last_download_time` - Set `filter.last_download_time` value, which
320 /// will be added to `filter.expires` and compared to `now()` at
321 /// [`Self::update_filters`] method.
322 /// * `is_enabled` - True if the filter is enabled.
323 /// * `is_trusted` - True if the filter is trusted.
324 /// * `filter_body` - Filter contents.
325 /// * `custom_title` - Filter may have customized title.
326 /// See [FilterListManager::install_custom_filter_list].
327 /// * `custom_description` - Filter may have customized description.
328 /// See [FilterListManager::install_custom_filter_list].
329 ///
330 /// # Failure
331 ///
332 /// Returns [`Err`] if `last_download_time` has unsupported format.
333 fn install_custom_filter_from_string(
334 &self,
335 download_url: String,
336 last_download_time: i64,
337 is_enabled: bool,
338 is_trusted: bool,
339 filter_body: String,
340 custom_title: Option<String>,
341 custom_description: Option<String>,
342 ) -> FLMResult<FullFilterList>;
343
344 /// Gets a list of [`ActiveRulesInfo`] from filters with `filter.is_enabled=true` flag.
345 fn get_active_rules(&self) -> FLMResult<Vec<ActiveRulesInfo>>;
346
347 /// Gets a list of [`ActiveRulesInfoRaw`] from filters with `filter.is_enabled=true` flag.
348 /// * `filter_by` - If empty, returns all active rules, otherwise returns intersection between `filter_by` and all active rules
349 fn get_active_rules_raw(&self, filter_by: Vec<FilterId>) -> FLMResult<Vec<ActiveRulesInfoRaw>>;
350
351 /// Gets a list of [`FilterListRulesRaw`] structures containing.
352 /// `rules` and `disabled_rules` as strings, directly from database fields.
353 ///
354 /// This method acts in the same way as the `IN` database operator. Only found entities will be returned
355 fn get_filter_rules_as_strings(&self, ids: Vec<FilterId>)
356 -> FLMResult<Vec<FilterListRulesRaw>>;
357
358 /// Reads the rule list for a specific filter in chunks, applying exceptions from the disabled_rules list on the fly.
359 /// The default size of the read buffer is 1 megabyte. But this size can be exceeded if a longer string appears in the list of filter rules.
360 /// The main purpose of this method is to reduce RAM consumption when reading large size filters.
361 ///
362 /// # Failure
363 ///
364 /// May return [`crate::FLMError::EntityNotFound()`] with [`FilterId`] if rule list is not found for such id
365 fn save_rules_to_file_blob<P: AsRef<Path>>(
366 &self,
367 filter_id: FilterId,
368 file_path: P,
369 ) -> FLMResult<()>;
370
371 /// Returns lists of disabled rules by list of filter IDs
372 fn get_disabled_rules(&self, ids: Vec<FilterId>) -> FLMResult<Vec<DisabledRulesRaw>>;
373
374 /// Sets a new proxy mode. Value will be applied on next method call
375 fn set_proxy_mode(&mut self, mode: RequestProxyMode);
376
377 /// Returns lists of rules count by list of filter IDs
378 fn get_rules_count(&self, ids: Vec<FilterId>) -> FLMResult<Vec<RulesCountByFilter>>;
379}