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 re | |||
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'"([^"\\]|\\[^"]|\\")*"' | |||
single_var_param_match=r'(?:-?\d+|"(?:[^"\\]|\\[^"]|\\")*")' | |||
@@ -1244,8 +1247,8 @@ view_created=False | |||
scope_filter='cppcms::filters::escape' | |||
view_name = '' | |||
declarations = StringIO.StringIO(); | |||
definitions = StringIO.StringIO(); | |||
declarations = StringIO(); | |||
definitions = StringIO(); | |||
inline_cpp_to = output_declaration | |||
inline_templates = "default" | |||
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_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); | |||
/// | |||
/// 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 | |||
/// | |||
bool empty() const; | |||
@@ -165,7 +189,11 @@ private: | |||
uint32_t secure_ : 1; | |||
uint32_t has_age_ : 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_exp; | |||
bool secure; | |||
bool httponly; | |||
bool use_samesite_none; | |||
bool use_samesite_lax; | |||
bool use_samesite_strict; | |||
bool remove_unknown_cookies; | |||
} cookies; | |||
cached_session(json::value const &v) | |||
@@ -173,6 +177,22 @@ namespace impl { | |||
cookies.use_age = cookies.use_exp = true; | |||
} | |||
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; | |||
struct cached_misc { | |||
@@ -108,6 +108,10 @@ struct cppcms_capi_cookie { | |||
std::string path; | |||
std::string domain; | |||
bool secure; | |||
bool httponly; | |||
bool has_samesite_none; | |||
bool has_samesite_lax; | |||
bool has_samesite_strict; | |||
bool has_expires; | |||
bool has_max_age; | |||
time_t expires; | |||
@@ -121,6 +125,10 @@ struct cppcms_capi_cookie { | |||
path(c.path()), | |||
domain(c.domain()), | |||
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_max_age(c.max_age_defined()), | |||
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_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" |
@@ -78,6 +78,46 @@ void cookie::browser_age() | |||
bool cookie::secure() const { return secure_; } | |||
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 | |||
{ | |||
if(name_.empty()) | |||
@@ -117,6 +157,15 @@ void cookie::write(std::ostream &out) const | |||
out<<"; Path="<<path_; | |||
if(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"; | |||
} | |||
@@ -127,21 +176,21 @@ std::ostream &operator<<(std::ostream &out,cookie const &c) | |||
} | |||
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) : | |||
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) : | |||
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) : | |||
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_), | |||
secure_(other.secure_), | |||
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_; | |||
has_age_=other.has_age_; | |||
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; | |||
} | |||
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() {} | |||
@@ -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 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); | |||
@@ -501,8 +505,11 @@ void session_interface::set_session_cookie(int64_t age,std::string const &data,s | |||
} | |||
} | |||
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) | |||
d->adapter->set_cookie(the_cookie); | |||
@@ -80,6 +80,7 @@ namespace cppcms { | |||
#endif | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
#include <errno.h> | |||
#include <fcntl.h> | |||
#include <unistd.h> | |||
@@ -108,11 +109,20 @@ namespace cppcms { | |||
int fd = open("/dev/urandom",O_RDONLY); | |||
if(!fd) | |||
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); | |||
} | |||
if(n!=int(len)) | |||
if(len > 0) { | |||
throw cppcms_error("Failed to read /dev/urandom"); | |||
} | |||
} | |||
} | |||
@@ -44,6 +44,37 @@ void basic_test() | |||
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); | |||
std::ostringstream ss; | |||
ss << c; | |||