From aad0f90a9daf4219b06e874d23efc923bc9b09b6 Mon Sep 17 00:00:00 2001 From: Omar Roth Date: Wed, 10 Apr 2019 16:58:46 -0500 Subject: [PATCH] Add 'sign_token' --- spec/helpers_spec.cr | 24 ++++++++++++++++++++++++ src/invidious/users.cr | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/spec/helpers_spec.cr b/spec/helpers_spec.cr index 307e52d2..215ffc76 100644 --- a/spec/helpers_spec.cr +++ b/spec/helpers_spec.cr @@ -1,4 +1,5 @@ require "kemal" +require "openssl/hmac" require "pg" require "spec" require "yaml" @@ -81,4 +82,27 @@ describe "Helpers" do produce_comment_reply_continuation("_cE8xSu6swE", "UC1AZY74-dGVPe6bfxFwwEMg", "UgyBUaRGHB9Jmt1dsUZ4AaABAg").should eq("EiYSC19jRTh4U3U2c3dFwAEByAEB4AEBogINKP___________wFAABgGMk0aSxIaVWd5QlVhUkdIQjlKbXQxZHNVWjRBYUFCQWciAggAKhhVQzFBWlk3NC1kR1ZQZTZiZnhGd3dFTWcyC19jRTh4U3U2c3dFQAFICg%3D%3D") end end + + describe "#sign_token" do + it "correctly signs a given hash" do + token = { + "session" => "v1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "expires" => 1554680038, + "scopes" => [ + ":notifications", + ":subscriptions/*", + "GET:tokens*", + ], + "signature" => "f//2hS20th8pALF305PJFK+D2aVtvefNnQheILHD2vU=", + } + sign_token("SECRET_KEY", token).should eq(token["signature"]) + + token = { + "session" => "v1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "scopes" => [":notifications", "POST:subscriptions/*"], + "signature" => "fNvXoT0MRAL9eE6lTE33CEg8HitYJDOL9a22rSN2Ihg=", + } + sign_token("SECRET_KEY", token).should eq(token["signature"]) + end + end end diff --git a/src/invidious/users.cr b/src/invidious/users.cr index 40f24870..ce0bd0ab 100644 --- a/src/invidious/users.cr +++ b/src/invidious/users.cr @@ -211,6 +211,25 @@ def create_response(user_id, operation, key, db, expire = 6.hours) return challenge, token end +def sign_token(key, hash) + string_to_sign = [] of String + hash.each do |key, value| + if key == "signature" + next + end + + case value + when Array + string_to_sign << "#{key}=#{value.sort.join(",")}" + else + string_to_sign << "#{key}=#{value}" + end + end + + string_to_sign = string_to_sign.sort.join("\n") + return Base64.encode(OpenSSL::HMAC.digest(:sha256, key, string_to_sign)).strip +end + def validate_response(challenge, token, user_id, operation, key, db, locale) if !challenge raise translate(locale, "Hidden field \"challenge\" is a required field")