Class: Shugoi::Core
- Inherits:
-
Object
- Object
- Shugoi::Core
- Defined in:
- lib/shugoi/core.rb
Overview
Évaluation d'une requête : pre-flight PoW challenge, /__sg_challenge, blocage headless. Parité avec core.ts (module Node).
Defined Under Namespace
Classes: Decision
Instance Method Summary collapse
-
#challenge_page ⇒ Object
Page challenge (tableau en commentaire + JS PoW inline).
-
#evaluate(ctx) ⇒ Decision?
Nil = laisser passer.
-
#initialize(config, pow, api_client) ⇒ Core
constructor
A new instance of Core.
Constructor Details
#initialize(config, pow, api_client) ⇒ Core
Returns a new instance of Core.
10 11 12 13 14 15 16 17 |
# File 'lib/shugoi/core.rb', line 10 def initialize(config, pow, api_client) @config = config @pow = pow @api_client = api_client @validation_valid = false @validation_failed = false @validation_warned_at = 0 end |
Instance Method Details
#challenge_page ⇒ Object
Page challenge (tableau en commentaire + JS PoW inline).
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/shugoi/core.rb', line 51 def challenge_page js = <<~JS (function(){ var P=new URLSearchParams(location.search); var salt=P.get('salt')||'', ts=P.get('ts')||'', diff=parseInt(P.get('diff')||'10',10), path=P.get('path')||'/'; var enc=new TextEncoder(); function bits(d){var l=0;for(var i=0;i<d.length;i++){var b=parseInt(d[i],16);if(b===0){l+=4;continue}var s=b.toString(2),z=0;while(z<s.length&&s[z]==='0')z++;l+=z;break}return l} var n=0; function step(){ crypto.subtle.digest('SHA-256',enc.encode(salt+':'+n.toString(16))).then(function(buf){ var h=Array.from(new Uint8Array(buf)).map(function(v){return v.toString(16).padStart(2,'0')}).join(''); if(bits(h)>=diff){var base=path;var q=(base.indexOf('?')>=0?'&':'?')+'sg_proof='+ts+':'+n.toString(16);location.replace(base+q)} else{n++;if(n<300000)step()} }).catch(function(){location.reload()}); } step(); })(); JS html = "<!--\n#{BLOCK_PAGE}-->\n<script>#{js}</script>" Decision.new(status: 200, content_type: "text/html", body: html, headers: {}) end |
#evaluate(ctx) ⇒ Decision?
Returns nil = laisser passer.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/shugoi/core.rb', line 21 def evaluate(ctx) path = ctx[:path].to_s return nil if @config.is_allowlisted?(path) # Route du challenge JS (le navigateur arrive ici après le 307). if path == "/__sg_challenge" return challenge_page end # Pre-flight PoW challenge (anti-curl/view-source). return nil if path.include?("/__shugoi/") || path.start_with?("/api/") ua = ctx[:ua].to_s if ua.match?(/Mozilla/i) && !@config.signing_secret.to_s.empty? proof = ctx[:sg_proof].to_s unless @pow.valid?(proof) return pow_challenge_307(ctx) end end # Blocage headless (UA). if ua.match?(/Mozilla/i) == false && @config.is_headless?(ua) @api_client.post_event(@config.site_key, "headless", "") return Decision.new(status: @config.block_status, content_type: "text/plain", body: BLOCK_PAGE, headers: {}) end nil end |