gsc-cli 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +410 -414
- data/bin/gsc +28067 -5661
- data/dist/gsc +29121 -5046
- data/lib/gsc/aio_hunter.rb +343 -0
- data/lib/gsc/answer_synthesizer.rb +157 -0
- data/lib/gsc/api.rb +53 -1
- data/lib/gsc/auth.rb +26 -0
- data/lib/gsc/brand_segmenter.rb +140 -0
- data/lib/gsc/cache_manager.rb +806 -0
- data/lib/gsc/cannibalization_analyzer.rb +141 -0
- data/lib/gsc/canonical_chains.rb +367 -0
- data/lib/gsc/citation_simulator.rb +339 -0
- data/lib/gsc/cli/aio_hunter.rb +154 -0
- data/lib/gsc/cli/analytics.rb +788 -0
- data/lib/gsc/cli/audit.rb +1976 -0
- data/lib/gsc/cli/base.rb +384 -0
- data/lib/gsc/cli/cache.rb +266 -0
- data/lib/gsc/cli/canonical.rb +223 -0
- data/lib/gsc/cli/citation_simulator.rb +152 -0
- data/lib/gsc/cli/dashboard.rb +354 -0
- data/lib/gsc/cli/doctor.rb +129 -0
- data/lib/gsc/cli/eeat.rb +125 -0
- data/lib/gsc/cli/ga4.rb +852 -0
- data/lib/gsc/cli/growth.rb +650 -0
- data/lib/gsc/cli/hreflang.rb +164 -0
- data/lib/gsc/cli/image_seo.rb +162 -0
- data/lib/gsc/cli/indexing.rb +458 -0
- data/lib/gsc/cli/intent_shift.rb +125 -0
- data/lib/gsc/cli/keyword_value.rb +134 -0
- data/lib/gsc/cli/keywords.rb +795 -0
- data/lib/gsc/cli/landing_roi.rb +308 -0
- data/lib/gsc/cli/low_ctr.rb +213 -0
- data/lib/gsc/cli/mobile_parity.rb +150 -0
- data/lib/gsc/cli/report.rb +100 -0
- data/lib/gsc/cli/rich_results.rb +172 -0
- data/lib/gsc/cli/schema_generate.rb +149 -0
- data/lib/gsc/cli/seasonal.rb +232 -0
- data/lib/gsc/cli/security.rb +153 -0
- data/lib/gsc/cli/setup.rb +1291 -0
- data/lib/gsc/cli/sitemap_tree.rb +143 -0
- data/lib/gsc/cli/skill_pack.rb +62 -0
- data/lib/gsc/cli/soft_404.rb +199 -0
- data/lib/gsc/cli/sparkline.rb +227 -0
- data/lib/gsc/cli/watchdog.rb +150 -0
- data/lib/gsc/cli/zombie_purger.rb +208 -0
- data/lib/gsc/cli.rb +707 -5265
- data/lib/gsc/cli_advanced.rb +987 -44
- data/lib/gsc/client.rb +17 -2
- data/lib/gsc/color.rb +16 -1
- data/lib/gsc/command_registry.rb +47 -9
- data/lib/gsc/config.rb +2 -2
- data/lib/gsc/ctr_curve.rb +115 -0
- data/lib/gsc/decay_predictor.rb +322 -0
- data/lib/gsc/doctor.rb +434 -0
- data/lib/gsc/eeat_auditor.rb +428 -0
- data/lib/gsc/entity_auditor.rb +229 -0
- data/lib/gsc/firewall_scanner.rb +733 -0
- data/lib/gsc/geo_auditor.rb +368 -0
- data/lib/gsc/google_trends.rb +8 -1
- data/lib/gsc/heading_validator.rb +283 -0
- data/lib/gsc/hreflang_validator.rb +412 -0
- data/lib/gsc/image_seo.rb +286 -0
- data/lib/gsc/indexing_queue.rb +179 -0
- data/lib/gsc/indexnow.rb +93 -0
- data/lib/gsc/intent_shift.rb +188 -0
- data/lib/gsc/internal_links.rb +153 -36
- data/lib/gsc/keyword_value.rb +191 -0
- data/lib/gsc/landing_roi.rb +195 -0
- data/lib/gsc/llms_generator.rb +343 -22
- data/lib/gsc/low_ctr_rewriter.rb +408 -0
- data/lib/gsc/mobile_parity.rb +222 -0
- data/lib/gsc/network_tracer.rb +8 -1
- data/lib/gsc/page_analyzer.rb +47 -7
- data/lib/gsc/prompts.rb +38 -29
- data/lib/gsc/questions_harvester.rb +178 -0
- data/lib/gsc/report_generator.rb +461 -0
- data/lib/gsc/rich_results.rb +388 -0
- data/lib/gsc/robots_checker.rb +46 -15
- data/lib/gsc/schema_generator.rb +788 -0
- data/lib/gsc/schema_validator.rb +36 -38
- data/lib/gsc/seasonal_predictor.rb +381 -0
- data/lib/gsc/security_scanner.rb +496 -0
- data/lib/gsc/serp_feature_detector.rb +359 -0
- data/lib/gsc/serp_preview.rb +108 -22
- data/lib/gsc/site_crawler.rb +113 -21
- data/lib/gsc/sitemap_loader.rb +15 -4
- data/lib/gsc/sitemap_tree.rb +301 -0
- data/lib/gsc/skill_pack.rb +195 -0
- data/lib/gsc/soft_404_analyzer.rb +385 -0
- data/lib/gsc/sparkline.rb +171 -0
- data/lib/gsc/speed_correlator.rb +416 -0
- data/lib/gsc/striking_playbook.rb +190 -0
- data/lib/gsc/title_optimizer.rb +420 -0
- data/lib/gsc/vault.rb +260 -0
- data/lib/gsc/version.rb +1 -1
- data/lib/gsc/watchdog.rb +235 -0
- data/lib/gsc/zombie_purger.rb +366 -0
- data/lib/gsc.rb +118 -0
- metadata +75 -1
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'json'
|
|
5
|
+
require_relative 'base'
|
|
6
|
+
require_relative '../security_scanner'
|
|
7
|
+
require_relative '../color'
|
|
8
|
+
|
|
9
|
+
module GSC
|
|
10
|
+
class CLI
|
|
11
|
+
module Security
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
def run(command, target, extra, options, api = nil, site_url = nil, hostname = nil)
|
|
15
|
+
target_url = target || options[:url] || hostname || (site_url ? site_url.sub(/^sc-domain:/, '') : nil) || (Config.default_domain rescue nil)
|
|
16
|
+
unless target_url
|
|
17
|
+
if options[:json]
|
|
18
|
+
puts JSON.pretty_generate({ error: 'Target URL or domain required. Example: gsc security https://mysite.com' })
|
|
19
|
+
else
|
|
20
|
+
puts Color.c("❌ Error: Target URL or domain required. Example: gsc security https://mysite.com", Color::RED, Color::BOLD)
|
|
21
|
+
end
|
|
22
|
+
return
|
|
23
|
+
end
|
|
24
|
+
target_url = "https://#{target_url}" unless target_url =~ %r{^https?://}
|
|
25
|
+
|
|
26
|
+
scanner = GSC::SecurityScanner.new(target_url, options)
|
|
27
|
+
result = scanner.audit
|
|
28
|
+
|
|
29
|
+
if options[:json]
|
|
30
|
+
puts JSON.pretty_generate(result)
|
|
31
|
+
return
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
render_security_audit(result, options)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def render_security_audit(data, options)
|
|
38
|
+
puts "\n" + Color.cyan("╔" + "═" * 78 + "╗")
|
|
39
|
+
puts Color.cyan("║") + Color.bold(" 🔒 SECURITY HEADERS & HTTPS MIXED CONTENT AUDITOR ") + Color.cyan("║")
|
|
40
|
+
puts Color.cyan("╚" + "═" * 78 + "╝")
|
|
41
|
+
puts Color.gray(" Target URL: ") + Color.bold(data[:target])
|
|
42
|
+
puts Color.gray(" Effective URL: ") + Color.dim(data[:effective_url].to_s)
|
|
43
|
+
|
|
44
|
+
# Score & Grade
|
|
45
|
+
grade_color = case data[:grade]
|
|
46
|
+
when 'A+', 'A' then Color::GREEN
|
|
47
|
+
when 'B' then Color::CYAN
|
|
48
|
+
when 'C' then Color::YELLOW
|
|
49
|
+
else Color::RED
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
puts Color.gray(" Security Posture: ") + Color.c("#{data[:score]}/100 [Grade #{data[:grade]}]", grade_color, Color::BOLD)
|
|
53
|
+
puts Color.gray(" Verdict: ") + Color.c(data[:verdict].to_s, grade_color)
|
|
54
|
+
puts Color.cyan("─" * 80)
|
|
55
|
+
|
|
56
|
+
# 1. SSL/TLS Certificate
|
|
57
|
+
ssl = data[:ssl] || {}
|
|
58
|
+
puts "\n" + Color.bold("🔐 SSL/TLS CERTIFICATE STATUS:")
|
|
59
|
+
if ssl[:status] == :valid
|
|
60
|
+
puts " • Status: " + Color.green(Color.bold("VALID & SECURE")) + Color.gray(" (#{ssl[:days_remaining]} days remaining)")
|
|
61
|
+
puts " • Valid Period: #{ssl[:valid_from][0..9]} → #{ssl[:valid_to][0..9]}"
|
|
62
|
+
puts " • Issuer: #{ssl[:issuer]}"
|
|
63
|
+
puts " • Subject / SAN: #{ssl[:subject]} (#{ssl[:san_count]} alternate names)"
|
|
64
|
+
elsif ssl[:status] == :not_https
|
|
65
|
+
puts " • Status: " + Color.red(Color.bold("NOT SERVED OVER HTTPS"))
|
|
66
|
+
else
|
|
67
|
+
puts " • Status: " + Color.red(Color.bold("WARNING: #{ssl[:message] || ssl[:status]}"))
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# 2. HSTS Preload Eligibility
|
|
71
|
+
hsts = data[:hsts_preload] || {}
|
|
72
|
+
puts "\n" + Color.bold("🚀 HSTS PRELOAD STATUS (Google Chrome Preload List):")
|
|
73
|
+
if hsts[:eligible]
|
|
74
|
+
puts " • Eligibility: " + Color.green(Color.bold("✓ ELIGIBLE FOR HSTS PRELOAD"))
|
|
75
|
+
puts " • Header: " + Color.dim(hsts[:current_header].to_s)
|
|
76
|
+
else
|
|
77
|
+
puts " • Eligibility: " + Color.yellow(Color.bold("NOT CURRENTLY ELIGIBLE"))
|
|
78
|
+
(hsts[:reasons] || []).each do |reason|
|
|
79
|
+
puts " ↳ " + Color.gray(reason)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# 3. Security Headers Audit Table
|
|
84
|
+
headers = data[:headers] || {}
|
|
85
|
+
puts "\n" + Color.bold("🛡️ ENTERPRISE SECURITY HEADERS:")
|
|
86
|
+
|
|
87
|
+
(headers[:present] || []).each do |p|
|
|
88
|
+
q_badge = case p[:quality]
|
|
89
|
+
when :optimal then Color.green("[OPTIMAL]")
|
|
90
|
+
when :acceptable then Color.cyan("[ACCEPTABLE]")
|
|
91
|
+
else Color.yellow("[SUBOPTIMAL]")
|
|
92
|
+
end
|
|
93
|
+
puts " ✓ #{Color.bold(p[:header].ljust(27))} #{q_badge} #{Color.dim(p[:details])}"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
(headers[:missing] || []).each do |m|
|
|
97
|
+
puts " ✗ #{Color.red(Color.bold(m[:header].ljust(27)))} #{Color.red("[MISSING -#{m[:weight]}pts]")} #{Color.gray(m[:desc])}"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# 4. Leakage Headers
|
|
101
|
+
leaks = headers[:leakage] || []
|
|
102
|
+
if leaks.any?
|
|
103
|
+
puts "\n" + Color.bold("⚠️ SERVER FINGERPRINTING & LEAKAGE HEADERS:")
|
|
104
|
+
leaks.each do |l|
|
|
105
|
+
puts " • #{Color.yellow(l[:header])}: #{Color.dim(l[:value])} #{Color.gray("(Reveals server version to attackers)")}"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# 5. Mixed Content
|
|
110
|
+
mixed = data[:mixed_content] || {}
|
|
111
|
+
puts "\n" + Color.bold("⚡ HTTPS MIXED CONTENT STATUS:")
|
|
112
|
+
if mixed[:total] == 0
|
|
113
|
+
puts " " + Color.green("✓ Zero mixed content detected! All scripts, frames, and media are securely loaded over HTTPS.")
|
|
114
|
+
else
|
|
115
|
+
if mixed[:active].any?
|
|
116
|
+
puts " 🚨 " + Color.red(Color.bold("ACTIVE MIXED CONTENT (#{mixed[:active].size} items - HARD BLOCKED BY BROWSERS):"))
|
|
117
|
+
mixed[:active].first(5).each do |item|
|
|
118
|
+
puts " • #{item[:type]}: #{Color.yellow(item[:url])}"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
if mixed[:passive].any?
|
|
122
|
+
puts " ⚠️ " + Color.yellow(Color.bold("PASSIVE MIXED CONTENT (#{mixed[:passive].size} images/media - DEGRADES PADLOCK):"))
|
|
123
|
+
mixed[:passive].first(5).each do |item|
|
|
124
|
+
puts " • #{item[:type]}: #{Color.dim(item[:url])}"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# 6. Recommendations
|
|
130
|
+
recs = data[:recommendations] || []
|
|
131
|
+
if recs.any?
|
|
132
|
+
puts "\n" + Color.bold("📋 ACTIONABLE SECURITY RECOMMENDATIONS:")
|
|
133
|
+
recs.each_with_index do |rec, idx|
|
|
134
|
+
puts " #{idx + 1}. #{rec}"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# 7. 1-Click Server Directives
|
|
139
|
+
rules = data[:server_rules] || {}
|
|
140
|
+
if rules[:nginx] && !rules[:nginx].empty?
|
|
141
|
+
puts "\n" + Color.cyan("─" * 80)
|
|
142
|
+
puts Color.bold("💻 1-CLICK SERVER FIX RULES (Nginx):")
|
|
143
|
+
puts Color.dim(rules[:nginx])
|
|
144
|
+
puts "\n" + Color.bold("💻 1-CLICK SERVER FIX RULES (Apache .htaccess):")
|
|
145
|
+
puts Color.dim(rules[:apache])
|
|
146
|
+
puts "\n" + Color.bold("💻 1-CLICK SERVER FIX RULES (Vercel / Netlify _headers):")
|
|
147
|
+
puts Color.dim(rules[:vercel_netlify])
|
|
148
|
+
end
|
|
149
|
+
puts Color.cyan("=" * 80) + "\n"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|