Skip to content
This repository has been archived by the owner on Jun 1, 2023. It is now read-only.

Enable Theme Access passwords for theme serve #2681

Merged
merged 4 commits into from
Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ From version 2.6.0, the sections in this file adhere to the [keep a changelog](h

## [Unreleased]

### Added
* [#2681](https://github.com/Shopify/shopify-cli/pull/2681): Enable Theme Access passwords for theme serve

## Version 2.31.0 - 2022-11-07

### Added
Expand Down
22 changes: 18 additions & 4 deletions lib/shopify_cli/theme/dev_server/proxy.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# frozen_string_literal: true

require "stringio"
require "time"
require "cgi"
Expand All @@ -20,6 +21,7 @@ class DevServer
"transfer-encoding",
"upgrade",
"content-security-policy",
"content-length",
]

class Proxy
Expand Down Expand Up @@ -54,14 +56,14 @@ def call(env)
"POST", env["PATH_INFO"],
headers: headers,
query: query,
form_data: form_data.merge(replace_templates).merge(_method: env["REQUEST_METHOD"]),
form_data: form_data.merge(replace_templates).merge(_method: env["REQUEST_METHOD"])
)
else
request(
env["REQUEST_METHOD"], env["PATH_INFO"],
headers: headers,
query: query,
body_stream: (env["rack.input"] if has_body?(headers)),
body_stream: (env["rack.input"] if has_body?(headers))
)
end

Expand Down Expand Up @@ -97,7 +99,7 @@ def has_body?(headers)

def bearer_token
Environment.storefront_renderer_auth_token ||
ShopifyCLI::DB.get(:storefront_renderer_production_exchange_token) ||
ShopifyCLI::DB.get(:storefront_renderer_production_exchange_token) ||
raise(KeyError, "storefront_renderer_production_exchange_token missing")
end

Expand Down Expand Up @@ -152,11 +154,13 @@ def add_session_cookie(cookie_header)

def secure_session_id_expired?
return true unless @secure_session_id && @last_session_cookie_refresh

Time.now - @last_session_cookie_refresh >= SESSION_COOKIE_MAX_AGE
end

def extract_secure_session_id_from_response_headers(headers)
return unless headers["set-cookie"]

headers["set-cookie"][SESSION_COOKIE_REGEXP, 1]
end

Expand All @@ -173,7 +177,7 @@ def secure_session_id

def get_response_headers(response, env)
response_headers = normalize_headers(
response.respond_to?(:headers) ? response.headers : response.to_hash
response.respond_to?(:headers) ? response.headers : response.to_hash,
)
# According to https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.1.3.1Acc
# should remove hop-by-hop header fields
Expand All @@ -196,6 +200,16 @@ def get_response_headers(response, env)

def request(method, path, headers: nil, query: [], form_data: nil, body_stream: nil)
uri = URI.join("https://#{shop}", path)

if Environment.theme_access_password?
headers = headers ? headers.slice("ACCEPT", "CONTENT-TYPE", "CONTENT-LENGTH", "Cookie") : {}
headers.merge!({
"X-Shopify-Access-Token" => Environment.admin_auth_token,
"X-Shopify-Shop" => shop,
})
uri = URI.join("https://#{ThemeAccessAPI::BASE_URL}", "cli/sfr#{path}")
end

uri.query = URI.encode_www_form(query + [[:_fd, 0], [:pb, 0]])

@ctx.debug("Proxying #{method} #{uri}")
Expand Down
49 changes: 38 additions & 11 deletions test/shopify-cli/theme/dev_server/proxy_test.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# frozen_string_literal: true

require "test_helper"
require "shopify_cli/theme/dev_server/proxy"
require "shopify_cli/theme/development_theme"
Expand Down Expand Up @@ -51,6 +52,32 @@ def test_get_is_proxied_to_online_store
request.get("/")
end

def test_get_is_proxied_to_theme_access_api_when_password_is_provided
Environment.stubs(:theme_access_password?).returns(true)
Environment.stubs(:store).returns("https://dev-theme-server-store.myshopify.com")
stub_request(:head, "https://theme-kit-access.shopifyapps.com/cli/sfr/?_fd=0&pb=0&preview_theme_id=123456789")
.with(
headers: { "X-Shopify-Shop" => "https://dev-theme-server-store.myshopify.com" },
)
.to_return(
status: 200,
headers: { "Set-Cookie" => "_secure_session_id=#{SECURE_SESSION_ID}" },
)
stub_request(:get, "https://theme-kit-access.shopifyapps.com/cli/sfr/?_fd=0&pb=0")
.with(
headers: {
"Content-Length" => "0",
"Cookie" => "_secure_session_id=deadbeef",
"X-Shopify-Shop" => "https://dev-theme-server-store.myshopify.com",
},
)
.to_return(status: 200, body: "", headers: {})

request.get("/")

assert_requested(:get, "https://theme-kit-access.shopifyapps.com/cli/sfr/?_fd=0&pb=0")
end

def test_refreshes_session_cookie_on_expiry
stub_request(:get, "https://dev-theme-server-store.myshopify.com/?_fd=0&pb=0")
.with(
Expand Down Expand Up @@ -82,22 +109,22 @@ def test_update_session_cookie_when_returned_from_backend
.with(
headers: {
"Cookie" => "_secure_session_id=#{SECURE_SESSION_ID}",
}
},
)
.to_return(
status: 200,
body: "",
headers: {
"Set-Cookie" => "_secure_session_id=#{new_secure_session_id}",
}
},
)

# GET / passing the new session cookie
stub_request(:get, "https://dev-theme-server-store.myshopify.com/?_fd=0&pb=0")
.with(
headers: {
"Cookie" => "_secure_session_id=#{new_secure_session_id}",
}
},
)
.to_return(status: 200)

Expand All @@ -114,7 +141,7 @@ def test_form_data_is_proxied_to_online_store
},
headers: default_proxy_headers.merge(
"Content-Type" => "application/x-www-form-urlencoded",
)
),
)
.to_return(status: 200)

Expand All @@ -132,7 +159,7 @@ def test_multipart_is_proxied_to_online_store
headers: default_proxy_headers.merge(
"Content-Length" => "272",
"Content-Type" => "multipart/form-data; boundary=AaB03x",
)
),
)
.to_return(status: 200)

Expand Down Expand Up @@ -221,7 +248,7 @@ def test_replaces_secure_session_id_cookie
.with(
headers: {
"Cookie" => "_secure_session_id=#{SECURE_SESSION_ID}",
}
},
)

stub_session_id_request
Expand All @@ -234,7 +261,7 @@ def test_appends_secure_session_id_cookie
.with(
headers: {
"Cookie" => "cart_currency=CAD; secure_customer_sig=; _secure_session_id=#{SECURE_SESSION_ID}",
}
},
)

stub_session_id_request
Expand Down Expand Up @@ -274,7 +301,7 @@ def test_pass_pending_templates_to_storefront
"Host" => "dev-theme-server-store.myshopify.com",
"X-Forwarded-For" => "",
"User-Agent" => "Shopify CLI",
}
},
)
.to_return(status: 200, body: "PROXY RESPONSE")

Expand All @@ -301,7 +328,7 @@ def test_patching_store_urls
"layout/theme.liquid" => @theme["layout/theme.liquid"].read,
},
},
headers: { "User-Agent" => "Shopify CLI" }
headers: { "User-Agent" => "Shopify CLI" },
)
.to_return(status: 200, body: <<-PROXY_RESPONSE)
<html>
Expand Down Expand Up @@ -428,13 +455,13 @@ def stub_session_id_request
.with(
headers: {
"Host" => "dev-theme-server-store.myshopify.com",
}
},
)
.to_return(
status: 200,
headers: {
"Set-Cookie" => "_secure_session_id=#{SECURE_SESSION_ID}",
}
},
)
end
end
Expand Down