Résoudre reCAPTCHA Enterprise avec Ruby

Par solvethree4 min de lecture

Utilisez Net::HTTP de Ruby pour créer une tâche reCAPTCHA Enterprise et interroger son état jusqu’à ce qu’elle soit prête ou en échec. L’exemple ci-dessous appelle directement l’API REST de solvethree ; il ne nécessite pas de SDK Ruby.

Sur cette page

Configurer le site et l’environnement

  1. 1.

    Activer le profil de site

    Configurez le nom d’hôte cible dans la console solvethree et assurez-vous que son profil est actif pour votre espace de travail. L’envoi d’un nom d’hôte et d’une action ne crée pas de profil. Consultez la configuration du profil de site.

  2. 2.

    Définir les variables d’environnement

    Définissez SOLVETHREE_API_KEY sur la clé API de votre espace de travail et SOLVETHREE_PROXY sur l’URL du proxy HTTP ou HTTPS que vous utiliserez aussi pour envoyer le jeton à la cible. Conservez la clé sur le serveur.

  3. 3.

    Modifier les paramètres de l’exemple

    Remplacez accounts.example.com par le nom d’hôte cible, et non une URL complète, et remplacez login par l’action requise par cette cible. La requête utilise un seul proxy ; n’ajoutez pas aussi proxyCandidates. Omettez type et url. L’omission de recaptchaType sélectionne la valeur par défaut, enterprise-v3.

Enregistrez l’exemple sous solve.rb et exécutez-le avec Ruby après avoir défini ces variables. Il charge net/http, json et securerandom ; JSON gère le corps de la requête et les réponses de l’API.

Créer une seule fois, puis interroger l’identifiant de tâche

Ruby · une création et un nombre fini d’interrogations périodiques
require 'net/http'
require 'json'
require 'securerandom'

api = 'https://api.solvethree.com/v1'
input = {site: 'accounts.example.com', action: 'login', proxy: ENV.fetch('SOLVETHREE_PROXY'), requestId: SecureRandom.uuid}
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + 180
call = lambda do |method, path, body = nil|
  remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
  raise 'Local deadline reached' if remaining <= 0
  uri = URI(api + path)
  request = method == :post ? Net::HTTP::Post.new(uri) : Net::HTTP::Get.new(uri)
  request['Authorization'] = 'Bearer ' + ENV.fetch('SOLVETHREE_API_KEY')
  request['Accept'] = 'application/json'
  if body
    request['Content-Type'] = 'application/json'
    request.body = JSON.generate(body)
  end
  # Net::HTTP's own proxy configuration is separate from input[:proxy].
  http = Net::HTTP.new(uri.hostname, uri.port, nil)
  http.use_ssl = uri.scheme == 'https'
  http.open_timeout = [10, remaining].min
  http.read_timeout = [25, remaining].min
  http.write_timeout = [25, remaining].min
  http.max_retries = 0
  response = http.request(request)
  raise "API HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)
  JSON.parse(response.body)
end

task_id = nil
begin
  result = call.call(:post, '/tasks?waitMs=0', input)
  task_id = result.fetch('id')
  while %w[pending solving].include?(result.fetch('status'))
    result = call.call(:get, '/tasks/' + URI.encode_www_form_component(task_id) + '?waitMs=15000')
    sleep(1) if %w[pending solving].include?(result.fetch('status'))
  end
  raise "Task failed: #{result['errorCode']}" unless result['status'] == 'ready'
  puts "Ready task: #{task_id}"
  # Submit result['solution']['token'] with its userAgent/secChUa and original proxy.
rescue StandardError => error
  warn "Recovery requestId=#{input[:requestId]} taskId=#{task_id || 'unknown'}"
  raise error
end

Le script envoie une seule requête de création, enregistre l’identifiant de tâche renvoyé et récupère cette tâche tant que son statut est pending ou solving. Seul ready fournit une solution utilisable. Chaque réponse doit avoir un statut HTTP de réussite avant que son corps soit analysé comme une réponse de réussite.

HTTPS est activé explicitement. Les nouvelles tentatives automatiques sont désactivées, et les redirections sont rejetées par la vérification du statut HTTP plutôt que suivies. Le proxy dans le corps de la tâche sert à la résolution ; il ne configure pas la connexion de Ruby à l’API solvethree.

L’échéance monotone partagée accorde à l’interrogation un budget local de 180 secondes. Les délais d’expiration de connexion, de lecture et d’écriture sont plafonnés selon le temps restant au démarrage de chaque requête. Considérez ce budget comme une limite d’interrogation, et non comme un délai strict d’annulation d’une requête en cours. La documentation Ruby Net::HTTP décrit les différents paramètres de délai d’expiration.

Envoyer le jeton avec son identité de navigateur

L’exemple affiche l’identifiant de la tâche prête, pas le jeton. Lisez solution.token dans le résultat prêt et placez-le dans le champ de jeton attendu par la requête cible. N’envoyez pas l’identifiant de tâche à la place.

Utilisez la valeur solution.userAgent renvoyée pour l’en-tête User-Agent et solution.secChUa pour Sec-CH-UA. Envoyez la requête à la cible prévue via le même proxy que celui fourni à cette tâche. Ne remplacez pas l’identité renvoyée par les en-têtes d’un autre navigateur.

Une tâche prête signifie que solvethree a généré une solution. Vérifiez séparément la réponse de la cible pour déterminer si elle a accepté votre requête applicative.

Gérer les échecs sans créer de tâches en double

Le script lève une erreur HTTP de l’API.

Examinez la réponse HTTP non réussie. Il s’agit d’une erreur au niveau de la requête, pas d’un résultat terminal de tâche.

Essayez ceci : Diagnostiquez cette réponse avant de réessayer. Ne renvoyez pas à répétition des paramètres invalides inchangés.

La tâche atteint le statut failed.

Examinez à la fois errorCode et error dans le résultat. Le message de l’exception levée par l’exemple ne contient que errorCode.

Essayez ceci : Cessez d’interroger cette tâche et corrigez la cause signalée. Les résolutions échouées sont remboursées ; un échec ne signifie pas nécessairement que le crédit est insuffisant.

La création expire avant la réception d’un identifiant de tâche.

Conservez le requestId de récupération écrit sur la sortie d’erreur standard. Une expiration ne prouve pas que la création a échoué.

Essayez ceci : Récupérez la tâche en envoyant une requête de tâche identique avec ce même identifiant de requête. Ne vous contentez pas de relancer le script : une nouvelle exécution génère un nouvel identifiant et peut créer une autre tâche.

L’interrogation atteint l’échéance locale ou perd sa connexion.

Conservez les identifiants de tâche et de requête consignés dans les journaux.

Essayez ceci : Récupérez la tâche dont vous connaissez l’identifiant avant d’en créer une autre. Une exception locale n’est pas un statut terminal de tâche.

Pour permettre une récupération après un redémarrage du processus, conservez l’identifiant de requête et les paramètres d’origine de la tâche avant d’envoyer le POST, puis conservez l’identifiant de tâche une fois reçu. Réutiliser un identifiant de requête avec des paramètres identiques renvoie la tâche existante ; modifier les paramètres tout en conservant cet identifiant provoque un conflit. Consultez la gestion des erreurs API pour l’étape de diagnostic suivante.

Lancez votre première tâche.

Démarrez avec $5 de crédit dans votre espace de travail.

Créer un espace de travail
Résoudre reCAPTCHA Enterprise avec Ruby · solvethree