Author | SHA1 | Message | Date |
---|---|---|---|
Artyom Beilis |
de995bae7a
|
Merge pull request #65 from mark-whiting/master
Support for the HttpOnly and SameSite directives on cookies. |
4 years ago |
Mark Whiting | 04aa46b2b0 | Added config options to set the HttpOnly and SameSite directives on the session cookie. | 4 years ago |
Mark Whiting | 571fc96ac6 | Added support for the HttpOnly and SameSite directives to cookies. | 4 years ago |
Artyom Beilis |
270634e69f
|
Merge pull request #44 from mgavin/cppcms_tmpl_cc_python2_fix
cppcms_tmpl_cc: |
5 years ago |
Artyom Beilis | 3e3cf43201 | Attempt to fix #43 failure to read from /dev/urandom | 5 years ago |
mgavin | ddc23a101b |
cppcms_tmpl_cc:
The shebang line at the top resolves to python3 on some sytems. This causes the import request to StringIO to fail with a ModuleNotFoundError. |
5 years ago |
@@ -11,7 +11,10 @@ | |||||
import os | import os | ||||
import re | import re | ||||
import sys | import sys | ||||
import StringIO | |||||
try: | |||||
from StringIO import StringIO | |||||
except ModuleNotFoundError: # StringIO moved to io in python 3 | |||||
from io import StringIO | |||||
str_match=r'"([^"\\]|\\[^"]|\\")*"' | str_match=r'"([^"\\]|\\[^"]|\\")*"' | ||||
single_var_param_match=r'(?:-?\d+|"(?:[^"\\]|\\[^"]|\\")*")' | single_var_param_match=r'(?:-?\d+|"(?:[^"\\]|\\[^"]|\\")*")' | ||||
@@ -1244,8 +1247,8 @@ view_created=False | |||||
scope_filter='cppcms::filters::escape' | scope_filter='cppcms::filters::escape' | ||||
view_name = '' | view_name = '' | ||||
declarations = StringIO.StringIO(); | |||||
definitions = StringIO.StringIO(); | |||||
declarations = StringIO(); | |||||
definitions = StringIO(); | |||||
inline_cpp_to = output_declaration | inline_cpp_to = output_declaration | ||||
inline_templates = "default" | inline_templates = "default" | ||||
output_template = output_definition | output_template = output_definition | ||||
@@ -155,6 +155,12 @@ CPPCMS_API long long cppcms_capi_cookie_expires(cppcms_capi_cookie const *cookie | |||||
CPPCMS_API int cppcms_capi_cookie_is_secure(cppcms_capi_cookie const *cookie); | CPPCMS_API int cppcms_capi_cookie_is_secure(cppcms_capi_cookie const *cookie); | ||||
CPPCMS_API int cppcms_capi_cookie_is_httponly(cppcms_capi_cookie const *cookie); | |||||
CPPCMS_API int cppcms_capi_cookie_samesite_none_defined(cppcms_capi_cookie const *cookie); | |||||
CPPCMS_API int cppcms_capi_cookie_samesite_lax_defined(cppcms_capi_cookie const *cookie); | |||||
CPPCMS_API int cppcms_capi_cookie_samesite_strict_defined(cppcms_capi_cookie const *cookie); | |||||
/// | /// | ||||
/// @} | /// @} | ||||
/// | /// | ||||
@@ -120,6 +120,30 @@ public: | |||||
void secure(bool v); | void secure(bool v); | ||||
/// | /// | ||||
/// Check if the httponly propertie is set on the cookies | |||||
/// | |||||
bool httponly() const; | |||||
/// | |||||
/// Set httponly property on the cookies | |||||
/// | |||||
void httponly(bool v); | |||||
/// | |||||
/// Check if one of the samesite properties is set on the cookies | |||||
/// | |||||
bool samesite_none() const; | |||||
bool samesite_lax() const; | |||||
bool samesite_strict() const; | |||||
/// | |||||
/// Set one of the samesite properties on the cookies | |||||
/// | |||||
void samesite_none(bool v); | |||||
void samesite_lax(bool v); | |||||
void samesite_strict(bool v); | |||||
/// | |||||
/// Check if cookie is not assigned - empty | /// Check if cookie is not assigned - empty | ||||
/// | /// | ||||
bool empty() const; | bool empty() const; | ||||
@@ -165,7 +189,11 @@ private: | |||||
uint32_t secure_ : 1; | uint32_t secure_ : 1; | ||||
uint32_t has_age_ : 1; | uint32_t has_age_ : 1; | ||||
uint32_t has_expiration_: 1; | uint32_t has_expiration_: 1; | ||||
CPPCMS_UNUSED_MEMBER uint32_t reserved_ : 29; | |||||
uint32_t httponly_ : 1; | |||||
uint32_t samesite_none_: 1; | |||||
uint32_t samesite_lax_: 1; | |||||
uint32_t samesite_strict_: 1; | |||||
CPPCMS_UNUSED_MEMBER uint32_t reserved_ : 25; | |||||
}; | }; | ||||
@@ -142,6 +142,10 @@ namespace impl { | |||||
bool use_age; | bool use_age; | ||||
bool use_exp; | bool use_exp; | ||||
bool secure; | bool secure; | ||||
bool httponly; | |||||
bool use_samesite_none; | |||||
bool use_samesite_lax; | |||||
bool use_samesite_strict; | |||||
bool remove_unknown_cookies; | bool remove_unknown_cookies; | ||||
} cookies; | } cookies; | ||||
cached_session(json::value const &v) | cached_session(json::value const &v) | ||||
@@ -173,6 +177,22 @@ namespace impl { | |||||
cookies.use_age = cookies.use_exp = true; | cookies.use_age = cookies.use_exp = true; | ||||
} | } | ||||
cookies.secure = v.get("session.cookies.secure",false); | cookies.secure = v.get("session.cookies.secure",false); | ||||
cookies.httponly = v.get("session.cookies.httponly", false); | |||||
std::string samesite = v.get("session.cookies.samesite", ""); | |||||
cookies.use_samesite_none = false; | |||||
cookies.use_samesite_lax = false; | |||||
cookies.use_samesite_strict = false; | |||||
if (samesite == "none") { | |||||
cookies.use_samesite_none = true; | |||||
} else if (samesite == "lax") { | |||||
cookies.use_samesite_lax = true; | |||||
} else if (samesite == "strict") { | |||||
cookies.use_samesite_strict = true; | |||||
} else if (!samesite.empty()) { | |||||
BOOSTER_WARNING("cppcms") << "Invalid session.cookies.samesite" | |||||
"if set should be one of 'none', 'lax', or 'strict'; defaults to unset"; | |||||
} | |||||
} | } | ||||
} session; | } session; | ||||
struct cached_misc { | struct cached_misc { | ||||
@@ -108,6 +108,10 @@ struct cppcms_capi_cookie { | |||||
std::string path; | std::string path; | ||||
std::string domain; | std::string domain; | ||||
bool secure; | bool secure; | ||||
bool httponly; | |||||
bool has_samesite_none; | |||||
bool has_samesite_lax; | |||||
bool has_samesite_strict; | |||||
bool has_expires; | bool has_expires; | ||||
bool has_max_age; | bool has_max_age; | ||||
time_t expires; | time_t expires; | ||||
@@ -121,6 +125,10 @@ struct cppcms_capi_cookie { | |||||
path(c.path()), | path(c.path()), | ||||
domain(c.domain()), | domain(c.domain()), | ||||
secure(c.secure()), | secure(c.secure()), | ||||
httponly(c.httponly()), | |||||
has_samesite_none(c.samesite_none()), | |||||
has_samesite_lax(c.samesite_lax()), | |||||
has_samesite_strict(c.samesite_strict()), | |||||
has_expires(c.expires_defined()), | has_expires(c.expires_defined()), | ||||
has_max_age(c.max_age_defined()), | has_max_age(c.max_age_defined()), | ||||
expires(c.expires()), | expires(c.expires()), | ||||
@@ -764,4 +772,10 @@ long long cppcms_capi_cookie_expires(cppcms_capi_cookie const *cookie) { return | |||||
int cppcms_capi_cookie_is_secure(cppcms_capi_cookie const *cookie) { return cookie ? cookie->secure: -1; } | int cppcms_capi_cookie_is_secure(cppcms_capi_cookie const *cookie) { return cookie ? cookie->secure: -1; } | ||||
int cppcms_capi_cookie_is_httponly(cppcms_capi_cookie const *cookie) { return cookie ? cookie->httponly: -1; } | |||||
int cppcms_capi_cookie_samesite_none_defined(cppcms_capi_cookie const *cookie) { return cookie ? cookie->has_samesite_none: -1; } | |||||
int cppcms_capi_cookie_samesite_lax_defined(cppcms_capi_cookie const *cookie) { return cookie ? cookie->has_samesite_lax: -1; } | |||||
int cppcms_capi_cookie_samesite_strict_defined(cppcms_capi_cookie const *cookie) { return cookie ? cookie->has_samesite_strict: -1; } | |||||
} // extern "C" | } // extern "C" |
@@ -78,6 +78,46 @@ void cookie::browser_age() | |||||
bool cookie::secure() const { return secure_; } | bool cookie::secure() const { return secure_; } | ||||
void cookie::secure(bool secure) { secure_ = secure ? 1: 0; } | void cookie::secure(bool secure) { secure_ = secure ? 1: 0; } | ||||
bool cookie::httponly() const { return httponly_; } | |||||
void cookie::httponly(bool httponly) { httponly_ = httponly ? 1 : 0; } | |||||
bool cookie::samesite_none() const { return samesite_none_; } | |||||
bool cookie::samesite_lax() const { return samesite_lax_; } | |||||
bool cookie::samesite_strict() const { return samesite_strict_; } | |||||
void cookie::samesite_none(bool v) | |||||
{ | |||||
if (v) { | |||||
samesite_none_ = 1; | |||||
samesite_lax_ = 0; | |||||
samesite_strict_ = 0; | |||||
} else { | |||||
samesite_none_ = 0; | |||||
} | |||||
} | |||||
void cookie::samesite_lax(bool v) | |||||
{ | |||||
if (v) { | |||||
samesite_none_ = 0; | |||||
samesite_lax_ = 1; | |||||
samesite_strict_ = 0; | |||||
} else { | |||||
samesite_lax_ = 0; | |||||
} | |||||
} | |||||
void cookie::samesite_strict(bool v) | |||||
{ | |||||
if (v) { | |||||
samesite_none_ = 0; | |||||
samesite_lax_ = 0; | |||||
samesite_strict_ = 1; | |||||
} else { | |||||
samesite_strict_ = 0; | |||||
} | |||||
} | |||||
void cookie::write(std::ostream &out) const | void cookie::write(std::ostream &out) const | ||||
{ | { | ||||
if(name_.empty()) | if(name_.empty()) | ||||
@@ -117,6 +157,15 @@ void cookie::write(std::ostream &out) const | |||||
out<<"; Path="<<path_; | out<<"; Path="<<path_; | ||||
if(secure_) | if(secure_) | ||||
out<<"; Secure"; | out<<"; Secure"; | ||||
if(httponly_) | |||||
out<<"; HttpOnly"; | |||||
// The samesite_*_ setters guarantee that only one of the following is set. | |||||
if(samesite_none_) | |||||
out<<"; SameSite=None"; | |||||
if(samesite_lax_) | |||||
out<<"; SameSite=Lax"; | |||||
if(samesite_strict_) | |||||
out<<"; SameSite=Strict"; | |||||
out<<"; Version=1"; | out<<"; Version=1"; | ||||
} | } | ||||
@@ -127,21 +176,21 @@ std::ostream &operator<<(std::ostream &out,cookie const &c) | |||||
} | } | ||||
cookie::cookie(std::string name,std::string value) : | cookie::cookie(std::string name,std::string value) : | ||||
name_(name), value_(value), secure_(0), has_age_(0), has_expiration_(0) | |||||
name_(name), value_(value), secure_(0), has_age_(0), has_expiration_(0), httponly_(0), samesite_none_(0), samesite_lax_(0), samesite_strict_(0) | |||||
{ | { | ||||
} | } | ||||
cookie::cookie(std::string name,std::string value,unsigned age) : | cookie::cookie(std::string name,std::string value,unsigned age) : | ||||
name_(name), value_(value), max_age_(age), secure_(0), has_age_(1), has_expiration_(0) | |||||
name_(name), value_(value), max_age_(age), secure_(0), has_age_(1), has_expiration_(0), httponly_(0), samesite_none_(0), samesite_lax_(0), samesite_strict_(0) | |||||
{ | { | ||||
} | } | ||||
cookie::cookie(std::string name,std::string value,unsigned age,std::string path,std::string domain,std::string comment) : | cookie::cookie(std::string name,std::string value,unsigned age,std::string path,std::string domain,std::string comment) : | ||||
name_(name), value_(value), path_(path),domain_(domain),comment_(comment),max_age_(age), secure_(0), has_age_(1), has_expiration_(0) | |||||
name_(name), value_(value), path_(path),domain_(domain),comment_(comment),max_age_(age), secure_(0), has_age_(1), has_expiration_(0), httponly_(0), samesite_none_(0), samesite_lax_(0), samesite_strict_(0) | |||||
{ | { | ||||
} | } | ||||
cookie::cookie(std::string name,std::string value,std::string path,std::string domain,std::string comment) : | cookie::cookie(std::string name,std::string value,std::string path,std::string domain,std::string comment) : | ||||
name_(name), value_(value), path_(path),domain_(domain),comment_(comment), secure_(0), has_age_(0), has_expiration_(0) | |||||
name_(name), value_(value), path_(path),domain_(domain),comment_(comment), secure_(0), has_age_(0), has_expiration_(0), httponly_(0), samesite_none_(0), samesite_lax_(0), samesite_strict_(0) | |||||
{ | { | ||||
} | } | ||||
@@ -155,7 +204,11 @@ cookie::cookie(cookie const &other) : | |||||
max_age_(other.max_age_), | max_age_(other.max_age_), | ||||
secure_(other.secure_), | secure_(other.secure_), | ||||
has_age_(other.has_age_), | has_age_(other.has_age_), | ||||
has_expiration_(other.has_expiration_) | |||||
has_expiration_(other.has_expiration_), | |||||
httponly_(other.httponly_), | |||||
samesite_none_(other.samesite_none_), | |||||
samesite_lax_(other.samesite_lax_), | |||||
samesite_strict_(other.samesite_strict_) | |||||
{ | { | ||||
} | } | ||||
@@ -171,10 +224,14 @@ cookie const &cookie::operator=(cookie const &other) | |||||
secure_=other.secure_; | secure_=other.secure_; | ||||
has_age_=other.has_age_; | has_age_=other.has_age_; | ||||
has_expiration_ = other.has_expiration_; | has_expiration_ = other.has_expiration_; | ||||
httponly_ = other.httponly_; | |||||
samesite_none_ = other.samesite_none_; | |||||
samesite_lax_ = other.samesite_lax_; | |||||
samesite_strict_ = other.samesite_strict_; | |||||
return *this; | return *this; | ||||
} | } | ||||
cookie::cookie() : secure_(0), has_age_(0), has_expiration_(0) {} | |||||
cookie::cookie() : secure_(0), has_age_(0), has_expiration_(0), httponly_(0), samesite_none_(0), samesite_lax_(0), samesite_strict_(0) {} | |||||
cookie::~cookie() {} | cookie::~cookie() {} | ||||
@@ -481,6 +481,10 @@ void session_interface::set_session_cookie(int64_t age,std::string const &data,s | |||||
bool use_exp = cached_settings().session.cookies.use_exp; | bool use_exp = cached_settings().session.cookies.use_exp; | ||||
bool secure = cached_settings().session.cookies.secure; | bool secure = cached_settings().session.cookies.secure; | ||||
bool httponly = cached_settings().session.cookies.httponly; | |||||
bool use_samesite_none = cached_settings().session.cookies.use_samesite_none; | |||||
bool use_samesite_lax = cached_settings().session.cookies.use_samesite_lax; | |||||
bool use_samesite_strict = cached_settings().session.cookies.use_samesite_strict; | |||||
http::cookie the_cookie(cookie_name,util::urlencode(data),path,domain); | http::cookie the_cookie(cookie_name,util::urlencode(data),path,domain); | ||||
@@ -501,8 +505,11 @@ void session_interface::set_session_cookie(int64_t age,std::string const &data,s | |||||
} | } | ||||
} | } | ||||
the_cookie.secure(secure); | the_cookie.secure(secure); | ||||
the_cookie.httponly(httponly); | |||||
the_cookie.samesite_none(use_samesite_none); | |||||
the_cookie.samesite_lax(use_samesite_lax); | |||||
the_cookie.samesite_strict(use_samesite_strict); | |||||
if(d->adapter) | if(d->adapter) | ||||
d->adapter->set_cookie(the_cookie); | d->adapter->set_cookie(the_cookie); | ||||
@@ -80,6 +80,7 @@ namespace cppcms { | |||||
#endif | #endif | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <errno.h> | |||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
@@ -108,11 +109,20 @@ namespace cppcms { | |||||
int fd = open("/dev/urandom",O_RDONLY); | int fd = open("/dev/urandom",O_RDONLY); | ||||
if(!fd) | if(!fd) | ||||
throw cppcms_error("Failed to open /dev/urandom"); | throw cppcms_error("Failed to open /dev/urandom"); | ||||
n = read(fd,ptr,len); | |||||
while(len > 0) { | |||||
n = read(fd,ptr,len); | |||||
if(n < 0 && errno == EINTR) | |||||
continue; | |||||
if(n <= 0) | |||||
break; | |||||
ptr = static_cast<char *>(ptr) + n; | |||||
len -= n; | |||||
} | |||||
close(fd); | close(fd); | ||||
} | } | ||||
if(n!=int(len)) | |||||
if(len > 0) { | |||||
throw cppcms_error("Failed to read /dev/urandom"); | throw cppcms_error("Failed to read /dev/urandom"); | ||||
} | |||||
} | } | ||||
} | } | ||||
@@ -44,6 +44,37 @@ void basic_test() | |||||
TEST(ss.str()=="Set-Cookie:a=b; Version=1"); | TEST(ss.str()=="Set-Cookie:a=b; Version=1"); | ||||
} | } | ||||
{ | { | ||||
c.httponly(true); | |||||
std::ostringstream ss; | |||||
ss << c; | |||||
TEST(ss.str()=="Set-Cookie:a=b; HttpOnly; Version=1"); | |||||
} | |||||
{ | |||||
c.samesite_none(true); | |||||
std::ostringstream ss; | |||||
ss << c; | |||||
TEST(ss.str()=="Set-Cookie:a=b; HttpOnly; SameSite=None; Version=1"); | |||||
} | |||||
{ | |||||
c.samesite_lax(true); | |||||
std::ostringstream ss; | |||||
ss << c; | |||||
TEST(ss.str()=="Set-Cookie:a=b; HttpOnly; SameSite=Lax; Version=1"); | |||||
} | |||||
{ | |||||
c.samesite_strict(true); | |||||
std::ostringstream ss; | |||||
ss << c; | |||||
TEST(ss.str()=="Set-Cookie:a=b; HttpOnly; SameSite=Strict; Version=1"); | |||||
} | |||||
{ | |||||
c.httponly(false); | |||||
c.samesite_strict(false); | |||||
std::ostringstream ss; | |||||
ss << c; | |||||
TEST(ss.str()=="Set-Cookie:a=b; Version=1"); | |||||
} | |||||
{ | |||||
c.max_age(10); | c.max_age(10); | ||||
std::ostringstream ss; | std::ostringstream ss; | ||||
ss << c; | ss << c; | ||||