Skip to content

Instantly share code, notes, and snippets.

@rodionovd
Last active July 19, 2016 06:58
Show Gist options
  • Select an option

  • Save rodionovd/4113ed644a078913c606 to your computer and use it in GitHub Desktop.

Select an option

Save rodionovd/4113ed644a078913c606 to your computer and use it in GitHub Desktop.

Revisions

  1. rodionovd revised this gist Jan 26, 2016. 1 changed file with 3 additions and 4 deletions.
    7 changes: 3 additions & 4 deletions shopcurbside-challenge.rb
    Original file line number Diff line number Diff line change
    @@ -50,14 +50,13 @@ def fetch_secrets(node="start", session)
    return body["secret"] if body.key? "secret"
    # It's not a leaf, but a regular node, so go down and ask siblings
    # for their secrets
    secrets = ""
    siblings = body["next"]
    # Caveat: some nodes have only one sibling which is represented as a
    # plain string; we wrap it into a single-item array for consistency
    siblings = Array(siblings) if siblings.is_a? String
    for buddy in siblings
    secrets << fetch_secrets(buddy, session)
    end
    secrets = siblings.map { |buddy|
    fetch_secrets(buddy, session)
    }.join("")
    return secrets
    rescue StandardError => e
    puts "HTTP Request failed: #{e.message}"
  2. rodionovd revised this gist Jan 21, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion shopcurbside-challenge.rb
    Original file line number Diff line number Diff line change
    @@ -64,7 +64,7 @@ def fetch_secrets(node="start", session)
    end
    end

    puts "Fetching the Curbside's secrets. It may take a while, so go grab some coffie ☕️"
    puts "Fetching the Curbside's secrets. It may take a while, so go grab some coffee ☕️"
    secrets = fetch_secrets(acquire_session)
    puts "Got it: \"#{secrets}\"!"

  3. rodionovd revised this gist Jan 21, 2016. 1 changed file with 41 additions and 41 deletions.
    82 changes: 41 additions & 41 deletions shopcurbside-challenge.rb
    Original file line number Diff line number Diff line change
    @@ -10,58 +10,58 @@
    # Due to the nature of this token -- it's valid for 10 requests only -- we'll
    # call this function more than once.
    def acquire_session()
    endpoint = URI('http://challenge.shopcurbside.com/get-session')
    http = Net::HTTP.new(endpoint.host, endpoint.port)
    req = Net::HTTP::Get.new(endpoint)
    return http.request(req).body
    endpoint = URI('http://challenge.shopcurbside.com/get-session')
    http = Net::HTTP.new(endpoint.host, endpoint.port)
    req = Net::HTTP::Get.new(endpoint)
    return http.request(req).body
    end

    # Converts all keys of the given hash to lowercase.
    def lowecase_hash(hash)
    result = {}
    hash.each {|k, v|
    result.merge!({k.downcase => v})
    }
    return result
    result = {}
    hash.each {|k, v|
    result.merge!({k.downcase => v})
    }
    return result
    end

    # The whole puzzle is a tree: you receive either a node containing URLs
    # of its sibling nodes or a leaf containing a single secret character.
    # This function will traverse the tree recursively and fetch all the secrets it
    # hides.
    def fetch_secrets(node="start", session)
    begin
    uri = URI("http://challenge.shopcurbside.com/#{node}")
    http = Net::HTTP.new(uri.host, uri.port)
    req = Net::HTTP::Get.new(uri)
    req.add_field("Session", session)
    res = http.request(req)
    body = JSON.parse(res.body)
    # In some nodes there're keys with mixed capitalization
    # (e.g. "neXT" vs "nExt" vs "next"), so here's a workaround
    body = lowecase_hash(body)
    # A session token lasts for only 10 requests, and we have to
    # renew it once in a while
    if body.key?("error") # TODO(rodionovd): maybe check an actual error msg?
    return fetch_secrets(node, acquire_session)
    end
    # So this's a leaf of the tree and we just pop up a secret value
    return body["secret"] if body.key? "secret"
    # It's not a leaf, but a regular node, so go down and ask siblings
    # for their secrets
    secrets = ""
    siblings = body["next"]
    # Caveat: some nodes have only one sibling which is represented as a
    # plain string; we wrap it into a single-item array for consistency
    siblings = Array(siblings) if siblings.is_a? String
    for buddy in siblings
    secrets << fetch_secrets(buddy, session)
    end
    return secrets
    rescue StandardError => e
    puts "HTTP Request failed: #{e.message}"
    end
    begin
    uri = URI("http://challenge.shopcurbside.com/#{node}")
    http = Net::HTTP.new(uri.host, uri.port)
    req = Net::HTTP::Get.new(uri)
    req.add_field("Session", session)
    res = http.request(req)
    body = JSON.parse(res.body)
    # In some nodes there're keys with mixed capitalization
    # (e.g. "neXT" vs "nExt" vs "next"), so here's a workaround
    body = lowecase_hash(body)
    # A session token lasts for only 10 requests, and we have to
    # renew it once in a while
    if body.key?("error") # TODO(rodionovd): maybe check an actual error msg?
    return fetch_secrets(node, acquire_session)
    end
    # So this's a leaf of the tree and we just pop up a secret value
    return body["secret"] if body.key? "secret"
    # It's not a leaf, but a regular node, so go down and ask siblings
    # for their secrets
    secrets = ""
    siblings = body["next"]
    # Caveat: some nodes have only one sibling which is represented as a
    # plain string; we wrap it into a single-item array for consistency
    siblings = Array(siblings) if siblings.is_a? String
    for buddy in siblings
    secrets << fetch_secrets(buddy, session)
    end
    return secrets
    rescue StandardError => e
    puts "HTTP Request failed: #{e.message}"
    end
    end

    puts "Fetching the Curbside's secrets. It may take a while, so go grab some coffie ☕️"
  4. rodionovd created this gist Jan 21, 2016.
    71 changes: 71 additions & 0 deletions shopcurbside-challenge.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,71 @@
    #!/usr/bin/ruby
    #
    # (c) Dmitry Rodionov, 2016
    # http://internals.exposed

    require 'net/http'
    require 'json'

    # Sends a GET request to /get-session in order to acquire a new session token.
    # Due to the nature of this token -- it's valid for 10 requests only -- we'll
    # call this function more than once.
    def acquire_session()
    endpoint = URI('http://challenge.shopcurbside.com/get-session')
    http = Net::HTTP.new(endpoint.host, endpoint.port)
    req = Net::HTTP::Get.new(endpoint)
    return http.request(req).body
    end

    # Converts all keys of the given hash to lowercase.
    def lowecase_hash(hash)
    result = {}
    hash.each {|k, v|
    result.merge!({k.downcase => v})
    }
    return result
    end

    # The whole puzzle is a tree: you receive either a node containing URLs
    # of its sibling nodes or a leaf containing a single secret character.
    # This function will traverse the tree recursively and fetch all the secrets it
    # hides.
    def fetch_secrets(node="start", session)
    begin
    uri = URI("http://challenge.shopcurbside.com/#{node}")
    http = Net::HTTP.new(uri.host, uri.port)
    req = Net::HTTP::Get.new(uri)
    req.add_field("Session", session)
    res = http.request(req)
    body = JSON.parse(res.body)
    # In some nodes there're keys with mixed capitalization
    # (e.g. "neXT" vs "nExt" vs "next"), so here's a workaround
    body = lowecase_hash(body)
    # A session token lasts for only 10 requests, and we have to
    # renew it once in a while
    if body.key?("error") # TODO(rodionovd): maybe check an actual error msg?
    return fetch_secrets(node, acquire_session)
    end

    # So this's a leaf of the tree and we just pop up a secret value
    return body["secret"] if body.key? "secret"
    # It's not a leaf, but a regular node, so go down and ask siblings
    # for their secrets
    secrets = ""
    siblings = body["next"]
    # Caveat: some nodes have only one sibling which is represented as a
    # plain string; we wrap it into a single-item array for consistency
    siblings = Array(siblings) if siblings.is_a? String
    for buddy in siblings
    secrets << fetch_secrets(buddy, session)
    end
    return secrets
    rescue StandardError => e
    puts "HTTP Request failed: #{e.message}"
    end
    end

    puts "Fetching the Curbside's secrets. It may take a while, so go grab some coffie ☕️"
    secrets = fetch_secrets(acquire_session)
    puts "Got it: \"#{secrets}\"!"

    # > Apply at systemd@shopcurbside.com with your code