Verifikimi i një dërgese
`OpenEmail.verify_webhook_signature`: në kohë konstante, me një dritare kundër riluajtjes, dhe me ngjarjen e analizuar si rezultat.
Në një handler kërkese
Një URL webhook-u është publike. Çdo gjë në internet mund të bëjë POST me JSON të formës së duhur drejt saj, ndaj një handler që lexon type e ngjarjes pa kontrolluar nënshkrimin është një API shkrimi e hapur.
class OpenEmailWebhooksController < ActionController::API def create event = OpenEmail.verify_webhook_signature( payload: request.raw_post, headers: request.headers, secret: ENV.fetch("OPENEMAIL_WEBHOOK_SECRET"), tolerance_seconds: 300 ) Rails.logger.info("#{event[:type]} #{event[:data]}") head :no_content rescue OpenEmail::WebhookSignatureError head :bad_request endendJepni trupin E PAPËRPUNUAR, si String. Analizimi dhe serializimi sërish ndryshojnë renditjen e çelësave dhe hapësirat, dhe nënshkrimi nuk do të përputhet, prandaj një Hash, si params i Rails, ngre ArgumentError në vend që të kontrollohet. headers: merr një Hash me emrin e header-it me çfarëdo shkronjash, një env të Rack, ku header-i mbërrin si HTTP_X_OPENEMAIL_SIGNATURE, ose request.headers të Rails. Një vlerë që është Array lexohet nga elementi i saj i parë.
Dy gjëra që kjo i trajton, e që një kontroll i bërë me dorë zakonisht nuk i trajton: e krahason MAC-un në kohë konstante, që parashtesa e saktë të mos nxirret duke matur kohën, dhe e refuzon një dërgesë më të vjetër se tolerance_seconds: në cilindo drejtim, pesë minuta, veç nëse thoni ndryshe, që një kërkesë e kapur të mos jetë e riluajtshme përgjithmonë. tolerance_seconds: 0 e çaktivizon kontrollin e riluajtjes. Të dy këta defekte janë të heshtur. Një handler me cilindo prej tyre i kalon të gjitha testet që do t’ju shkonte mendja të shkruanit.
Ngre OpenEmail::WebhookSignatureError në çdo dështim: një header X-OpenEmail-Signature që mungon, një që nuk është në formën t=<seconds>,v1=<hex>, një vulë kohore jashtë dritares, ose një nënshkrim që nuk përputhet. Në sukses, kthen trupin e analizuar në një Hash me çelësa Symbol, id, type, createdAt dhe data, ndaj nuk ka një JSON.parse të dytë për ta gabuar.
Një secret: që mungon ose është bosh ngre në vend të kësaj ArgumentError, sepse ai është një gabim në konfigurimin tuaj dhe jo një dërgesë e keqe. Kapni vetëm OpenEmail::WebhookSignatureError dhe përgjigjuni me 400, që një server i konfiguruar gabim të përgjigjet me 500 dhe dërgesa të riprovohet sapo ta rregulloni.
Përdor OpenSSL nga biblioteka standarde, të cilën gem-i e ngarkon tashmë, ndaj nuk ka nevojë për asgjë tjetër.
Në një aplikacion Rack ose Sinatra
Jashtë Rails, jepni vetë env-in e Rack si headers: dhe lexojeni trupin e papërpunuar nga kërkesa.
require "openemail"require "rack" webhook = lambda do |env| event = OpenEmail.verify_webhook_signature( payload: Rack::Request.new(env).body.read, headers: env, secret: ENV.fetch("OPENEMAIL_WEBHOOK_SECRET") ) warn "#{event[:type]} #{event[:id]}" [204, {}, []]rescue OpenEmail::WebhookSignatureError [400, {"content-type" => "text/plain"}, ["bad signature"]]end run webhookVersioni Rack është një config.ru i plotë. Përgjigjuni shpejt në të dyja: një dërgesë që nuk merr përgjigje brenda 5 sekondave llogaritet si e dështuar dhe dërgohet sërish më vonë, ndaj ia kaloni punën një pune në sfond dhe përgjigjuni me një 2xx.
OpenEmail::WEBHOOK_SIGNATURE_HEADERS emërton tre header-at që mbart një dërgesë: X-OpenEmail-Signature, X-OpenEmail-Event me llojin e ngjarjes, dhe X-OpenEmail-Delivery me id-në e saj, të njëjtin id si në trup. Kjo id mbetet e njëjtë në çdo riprovim dhe riluajtje të ngjarjes, ndaj është ajo që duhet ruajtur kur anashkaloni ngjarjet që i keni trajtuar tashmë.
Ndërsa sekreti rrotullohet
webhooks.rotate_secret nuk ka dritare mbivendosjeje: dërgesat nënshkruhen me sekretin e ri që nga çasti kur ai kthehet. Vendosni fillimisht në prodhim një marrës që pranon cilindo nga dy sekretet, rrotulloni, ruajeni sekretin e ri aty ku e lexon marrësi, pastaj hiqni të vjetrin.
def verify_delivery(payload, headers) secrets = [ENV.fetch("OPENEMAIL_WEBHOOK_SECRET"), ENV["OPENEMAIL_WEBHOOK_SECRET_NEXT"]].compact secrets.each_with_index do |secret, index| return OpenEmail.verify_webhook_signature(payload:, headers:, secret:) rescue OpenEmail::WebhookSignatureError raise if index == secrets.size - 1 endendwebhooks.test dërgon një ngjarje sintetike të nënshkruar, ndaj thirreni pas rrotullimit për të provuar se sekreti i ri verifikohet para se të hiqni të vjetrin.