Skip to content

Commit

Permalink
fix: Fix cors headers (#7900)
Browse files Browse the repository at this point in the history
* centralize cors headers handling in perl code
* add Access-Control-Allow-Methods correctly
* add tests

* cleaned nginx prod configurations
* make docker nginx more close to production configuration

should fix:
- #7796
- #7901
  • Loading branch information
alexgarel committed Jan 6, 2023
1 parent a526086 commit 4aac6f6
Show file tree
Hide file tree
Showing 29 changed files with 814 additions and 445 deletions.
12 changes: 3 additions & 9 deletions cgi/auth.pl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use ProductOpener::Config qw/:all/;
use ProductOpener::Store qw/:all/;
use ProductOpener::Display qw/:all/;
use ProductOpener::HTTP qw/:all/;
use ProductOpener::Users qw/:all/;
use ProductOpener::Lang qw/:all/;

Expand Down Expand Up @@ -76,15 +77,8 @@

# The Access-Control-Allow-Origin header must be set to the value of the Origin header
my $r = Apache2::RequestUtil->request();
my $origin = $r->headers_in->{Origin} || '';

# Only allow requests from one of our subdomains to see if a user is logged in or not

if ($origin =~ /^https:\/\/[a-z0-9-.]+\.${server_domain}(:\d+)?$/) {
$r->err_headers_out->set("Access-Control-Allow-Credentials", "true");
$r->err_headers_out->set("Access-Control-Allow-Origin", $origin);
}

my $allow_credentials = 1;
write_cors_headers($allow_credentials);
print header(-status => $status, -type => 'application/json', -charset => 'utf-8');

# 2022-10-11 - The Open Food Facts Flutter app is expecting an empty body
Expand Down
4 changes: 3 additions & 1 deletion cgi/ingredients.pl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use ProductOpener::Store qw/:all/;
use ProductOpener::Index qw/:all/;
use ProductOpener::Display qw/:all/;
use ProductOpener::HTTP qw/:all/;
use ProductOpener::Tags qw/:all/;
use ProductOpener::Users qw/:all/;
use ProductOpener::Images qw/:all/;
Expand Down Expand Up @@ -79,7 +80,8 @@

$log->debug("JSON data output", {data => $data}) if $log->is_debug();

print header (-charset => 'UTF-8', -access_control_allow_origin => '*') . $data;
write_cors_headers();
print header (-charset => 'UTF-8') . $data;

exit(0);

3 changes: 2 additions & 1 deletion cgi/nutrients.pl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

use ProductOpener::Lang qw/:all/;
use ProductOpener::Display qw/:all/;
use ProductOpener::HTTP qw/:all/;
use ProductOpener::Food qw/:all/;
use ProductOpener::Tags qw/:all/;

Expand Down Expand Up @@ -108,10 +109,10 @@

my %result = (nutrients => \@table);
my $data = encode_json(\%result);
write_cors_headers();
print header(
-type => 'application/json',
-content_language => $lc,
-charset => 'utf-8',
-access_control_allow_origin => '*',
-cache_control => 'public, max-age: 86400'
) . $data;
3 changes: 2 additions & 1 deletion cgi/opensearch.pl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use ProductOpener::Store qw/:all/;
use ProductOpener::Index qw/:all/;
use ProductOpener::Display qw/:all/;
use ProductOpener::HTTP qw/:all/;
use ProductOpener::Users qw/:all/;
use ProductOpener::Products qw/:all/;
use ProductOpener::Food qw/:all/;
Expand Down Expand Up @@ -82,9 +83,9 @@
XML
;

write_cors_headers();
print header(
-type => 'application/opensearchdescription+xml',
-charset => 'utf-8',
-access_control_allow_origin => '*',
-cache_control => 'public, max-age: 10080'
) . $xml;
4 changes: 3 additions & 1 deletion cgi/packaging.pl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use ProductOpener::Store qw/:all/;
use ProductOpener::Index qw/:all/;
use ProductOpener::Display qw/:all/;
use ProductOpener::HTTP qw/:all/;
use ProductOpener::Tags qw/:all/;
use ProductOpener::Users qw/:all/;
use ProductOpener::Images qw/:all/;
Expand Down Expand Up @@ -79,7 +80,8 @@

$log->debug("JSON data output", {data => $data}) if $log->is_debug();

print header (-charset => 'UTF-8', -access_control_allow_origin => '*') . $data;
write_cors_headers();
print header (-charset => 'UTF-8') . $data;

exit(0);

4 changes: 3 additions & 1 deletion cgi/product_image_crop.pl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use ProductOpener::Store qw/:all/;
use ProductOpener::Index qw/:all/;
use ProductOpener::Display qw/:all/;
use ProductOpener::HTTP qw/:all/;
use ProductOpener::Tags qw/:all/;
use ProductOpener::Users qw/:all/;
use ProductOpener::Images qw/:all/;
Expand Down Expand Up @@ -128,7 +129,8 @@

$log->debug("JSON data output", {data => $data}) if $log->is_debug();

print header(-type => 'application/json', -charset => 'utf-8', -access_control_allow_origin => '*') . $data;
write_cors_headers();
print header(-type => 'application/json', -charset => 'utf-8') . $data;

exit(0);

11 changes: 7 additions & 4 deletions cgi/product_jqm_multilingual.pl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ =head1 DESCRIPTION
use ProductOpener::Store qw/:all/;
use ProductOpener::Index qw/:all/;
use ProductOpener::Display qw/:all/;
use ProductOpener::HTTP qw/:all/;
use ProductOpener::Tags qw/:all/;
use ProductOpener::Users qw/:all/;
use ProductOpener::Images qw/:all/;
Expand Down Expand Up @@ -126,8 +127,8 @@ =head1 DESCRIPTION
$response{status_verbose} = 'Edit against edit rules';

my $data = encode_json(\%response);

print header(-type => 'application/json', -charset => 'utf-8', -access_control_allow_origin => '*') . $data;
write_cors_headers();
print header(-type => 'application/json', -charset => 'utf-8') . $data;

exit(0);
}
Expand Down Expand Up @@ -228,7 +229,8 @@ =head1 DESCRIPTION

my $data = encode_json(\%response);

print header(-type => 'application/json', -charset => 'utf-8', -access_control_allow_origin => '*') . $data;
write_cors_headers();
print header(-type => 'application/json', -charset => 'utf-8') . $data;

exit(0);
}
Expand Down Expand Up @@ -443,7 +445,8 @@ =head1 DESCRIPTION

my $data = encode_json(\%response);

print header(-type => 'application/json', -charset => 'utf-8', -access_control_allow_origin => '*') . $data;
write_cors_headers();
print header(-type => 'application/json', -charset => 'utf-8') . $data;

exit(0);

4 changes: 3 additions & 1 deletion cgi/search.pl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use ProductOpener::Store qw/:all/;
use ProductOpener::Index qw/:all/;
use ProductOpener::Display qw/:all/;
use ProductOpener::HTTP qw/:all/;
use ProductOpener::Users qw/:all/;
use ProductOpener::Products qw/:all/;
use ProductOpener::Food qw/:all/;
Expand Down Expand Up @@ -805,7 +806,8 @@

my $data = encode_json(\%response);

print "Content-Type: application/json; charset=UTF-8\r\nAccess-Control-Allow-Origin: *\r\n\r\n" . $data;
write_cors_headers();
print "Content-Type: application/json; charset=UTF-8\r\n\r\n" . $data;
}

if (single_param('search_terms')) {
Expand Down
4 changes: 3 additions & 1 deletion cgi/session.pl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use ProductOpener::Store qw/:all/;
use ProductOpener::Index qw/:all/;
use ProductOpener::Display qw/:all/;
use ProductOpener::HTTP qw/:all/;
use ProductOpener::Users qw/:all/;
use ProductOpener::Lang qw/:all/;

Expand Down Expand Up @@ -94,7 +95,8 @@
}
my $data = encode_json(\%response);

print header(-type => 'application/json', -charset => 'utf-8', -access_control_allow_origin => '*') . $data;
write_cors_headers();
print header(-type => 'application/json', -charset => 'utf-8') . $data;

}
else {
Expand Down
2 changes: 1 addition & 1 deletion cgi/suggest.pl
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,10 @@ =head3 limit - max number of suggestions
my $data = encode_json(\@suggestions);

# send response
write_cors_headers();
print header(
-type => 'application/json',
-charset => 'utf-8',
-access_control_allow_origin => '*'
);
if ($cache_max_age) {
print header(-cache_control => 'public, max-age=' . $cache_max_age,);
Expand Down
1 change: 1 addition & 0 deletions conf/expires-no-json-xml.include
60 changes: 20 additions & 40 deletions conf/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
# Default server configuration
#

# we need to have main domain for CORS (see nginx-cors includes)
map $host $main_domain {
default ...;
~*.*\.(?<host_main_domain>[^.]+\.[^.]+) $host_main_domain;
}


server {
listen 80;
listen [::]:80;
Expand All @@ -31,40 +38,8 @@ server {
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;

# Warning: headers added by add_header are overriden by
# other add_header directives at the same level.
#location ~* \.(json|csv)$ {
# add_header Access-Control-Allow-Origin *;
#}

location /data/ {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,If-None-Match';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header Access-Control-Max-Age 1728000;
add_header Content-Type 'text/plain; charset=utf-8';
add_header Content-Length 0;
return 204;
}
if ($request_method = 'POST') {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,If-None-Match';
add_header Access-Control-Expose-Headers 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,If-None-Match';
add_header Access-Control-Expose-Headers 'Content-Length,Content-Range';
}
include conf.d/off.cors-headers.include;
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
Expand All @@ -73,33 +48,38 @@ server {
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;

# handling expirations
include conf.d/expires-no-json-xml.include;

location ~ ^/images/products/ {
include conf.d/off.cors-headers.include;
add_header Link "<https://creativecommons.org/licenses/by-sa/3.0/>; rel='license'; title='CC-BY-SA 3.0'";
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,If-None-Match';
add_header Access-Control-Expose-Headers 'Content-Length,Content-Range';
}

# Static files are served directly by NGINX

location ~ ^/(.well-known|fonts|images|js|css|rss|data|files|resources)/ {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
add_header Access-Control-Allow-Origin *;
#add_header Access-Control-Allow-Origin *;
try_files $uri $uri/ =404;
}

location ~ /(favicon\.ico|robots\.txt)$ {
include conf.d/off.cors-headers.include;
try_files $uri $uri/ =404;
}

# redirects of some locations
include conf.d/off.locations-redirects.include;

# Dynamically generated files and CGI scripts are passed
# to the Apache + mod_perl server running on the backend container

# this is the internal Docker DNS, cache only for 30s
resolver 127.0.0.11 valid=30s;
# this is the internal Docker DNS, cache only for 30s
resolver 127.0.0.11 valid=30s;
location ~ /donate\/.*$ {
include conf.d/off.cors-headers.include;
try_files $uri =404;
}
location / {
Expand Down
1 change: 1 addition & 0 deletions conf/nginx/expires-no-json-xml.conf
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
expires 10d;
# expires 1M;
access_log off;
# FIXME: add_header here may hide CORS headers (and other headers, we should better use map)
add_header Cache-Control "public";
}

Expand Down
Loading

0 comments on commit 4aac6f6

Please sign in to comment.