render_addon_screen( __( 'Vulnerability database', 'guardforge' ), __( 'The advisory database is served by GuardForge Pro, a separate add-on. This build carries no advisory source of its own, so there is nothing to list here. File integrity, the audit log and brute-force protection are unaffected.', 'guardforge' ), 'vuln_db' ); return; } // True only for an older add-on that hangs no filter and has no daily event to // ride on; the refresh card below then asks for a newer add-on. $guardforge_addon_outdated = false; if ( $guardforge_pro_feed ) { $guardforge_db = GUARDFORGE_Vuln_Db::instance(); // The two feeds share a table and each owns a `source`; the count belongs // to whichever one is talking. See GUARDFORGE_Vuln_Db::record_count. $guardforge_total = $guardforge_db->record_count(); // The same never_fetched/stale/failed/clean contract the free feed below // uses — see both classes' state. This screen still shows whatever the // mirror currently holds (below, with the freshness notice this drives); // it is the hardening-score row (register_score_item) that refuses to // grade the site on anything short of 'clean'. $guardforge_state = GUARDFORGE_Vuln_Db::state(); $guardforge_hits = $guardforge_db->find_matches(); $guardforge_last_fetch = (string) $guardforge_state['fetched_at']; $guardforge_delay_days = 0; $guardforge_action = 'guardforge_vulndb_refresh'; // The licensed feed carries its own consent: the owner bought and // activated a key for it. $guardforge_needs_consent = false; // Does the add-on keep the database up to date on its own schedule? A // current add-on hangs the filter at load and answers it with true while its // licence is active and its own switch is on, and leaves false otherwise, so // a switched-off add-on takes the daily line off the screen. Asked through the // filter and not through GUARDFORGE_Vuln_Feed::pro_updates_feed, which says // the same thing: that class is not in the wp.org build, and this is the // branch that runs there. if ( has_filter( 'guardforge/pro_updates_vuln_db' ) ) { $guardforge_daily = (bool) apply_filters( 'guardforge/pro_updates_vuln_db', false ); } else { // An add-on from before the filter (1.2.x) hangs nothing and has no switch // or event of its own: it downloads on this plugin's daily event, for as // long as that event is on the schedule, and not at all without it. So // the schedule is the answer. The event is named as a string, because // GUARDFORGE_Vuln_Feed::CRON_HOOK is not in the wp.org build either; // class-vuln-db-refresh-note-test.php holds the two names together. $guardforge_daily = (bool) wp_next_scheduled( 'guardforge_vulndb_cron' ); $guardforge_addon_outdated = ! $guardforge_daily; } } else { $guardforge_feed = GUARDFORGE_Vuln_Feed::instance(); // find_matches, not refresh_matches: rendering a screen is a GET, and // a GET has no business writing an option. The stored match set is // refreshed where it can actually change — when a pull lands. $guardforge_hits = $guardforge_feed->find_matches(); $guardforge_state = GUARDFORGE_Vuln_Feed::state(); $guardforge_total = (int) $guardforge_state['records']; $guardforge_last_fetch = (string) $guardforge_state['fetched_at']; $guardforge_delay_days = (int) $guardforge_state['delay_days']; $guardforge_action = 'guardforge_vulndb_free_refresh'; // No switch, no button: the free feed is the one download that reaches an // Avakode server, and nothing here may start it before the owner has said // yes on the Settings screen. $guardforge_needs_consent = ! GUARDFORGE_Vuln_Feed::consent_given(); // With the download switched on this plugin's own daily event is on the // schedule; with it off the button is not drawn at all, so nothing below // reads the answer. $guardforge_daily = true; } /* translators: %1$d is total advisory records, %2$d is records affecting this site. */ $guardforge_subtitle = sprintf( __( '%1$d records · %2$d affecting this site', 'guardforge' ), (int) $guardforge_total, (int) count( $guardforge_hits ) ); ?>
0 ? $guardforge_delay_days : GUARDFORGE_Vuln_Feed::DELAY_DAYS_DEFAULT ) ); ?>