Merge branch 'main' into v0.24-changes

This commit is contained in:
Kishore Nallan 2022-07-07 20:43:49 +05:30
commit f189ed7a31
8 changed files with 33 additions and 17 deletions

View File

@ -129,7 +129,7 @@ Here's a quick example showcasing how you can create a collection, index a docum
Let's begin by starting the Typesense server via Docker:
```
docker run -p 8108:8108 -v/tmp/data:/data typesense/typesense:0.23.0 --data-dir /data --api-key=Hu52dwsas2AdxdE
docker run -p 8108:8108 -v/tmp/data:/data typesense/typesense:0.23.1 --data-dir /data --api-key=Hu52dwsas2AdxdE
```
We have [API Clients](#api-clients) in a couple of languages, but let's use the Python client for this example.
@ -232,7 +232,7 @@ We welcome community contributions to add more official client libraries and int
You can use our [InstantSearch.js adapter](https://github.com/typesense/typesense-instantsearch-adapter)
to quickly build powerful search experiences, complete with filtering, sorting, pagination and more.
Here's how: [https://typesense.org/docs/0.23.0/guide/#search-ui](https://typesense.org/docs/0.23.0/guide/#search-ui)
Here's how: [https://typesense.org/docs/0.23.1/guide/#search-ui](https://typesense.org/docs/0.23.1/guide/#search-ui)
## FAQ

View File

@ -33,7 +33,7 @@ TYPESENSE_DEV_IMAGE="typesense-development:27-JUN-2022-1"
ARCH_NAME="amd64"
if [[ "$@" == *"--graviton2"* ]]; then
TYPESENSE_DEV_IMAGE="typesense-development-arm:03-DEC-2021-1"
TYPESENSE_DEV_IMAGE="typesense-development-arm:27-JUN-2022-1"
ARCH_NAME="arm64"
fi

View File

@ -117,6 +117,8 @@ private:
bool auth_against_key(const std::string& req_collection, const std::string& action,
const api_key_t &api_key, const bool search_only) const;
static bool regexp_match(const std::string& value, const std::string& regexp);
public:
static const size_t GENERATED_KEY_LEN = 32;

View File

@ -210,6 +210,7 @@ struct http_req {
uint64_t route_hash;
std::map<std::string, std::string> params;
std::vector<nlohmann::json> embedded_params_vec;
std::string api_auth_key;
bool first_chunk_aggregate;
std::atomic<bool> last_chunk_aggregate;
@ -247,10 +248,10 @@ struct http_req {
}
http_req(h2o_req_t* _req, const std::string & http_method, const std::string & path_without_query, uint64_t route_hash,
const std::map<std::string, std::string>& params,
std::vector<nlohmann::json>& embedded_params_vec, const std::string& body, const std::string& client_ip):
const std::map<std::string, std::string>& params, std::vector<nlohmann::json>& embedded_params_vec,
const std::string& api_auth_key, const std::string& body, const std::string& client_ip):
_req(_req), http_method(http_method), path_without_query(path_without_query), route_hash(route_hash),
params(params), embedded_params_vec(embedded_params_vec),
params(params), embedded_params_vec(embedded_params_vec), api_auth_key(api_auth_key),
first_chunk_aggregate(true), last_chunk_aggregate(false),
chunk_len(0), body(body), body_index(0), data(nullptr), ready(false),
log_index(0), is_diposed(false), client_ip(client_ip) {

View File

@ -22,7 +22,6 @@ class HttpServer;
struct h2o_custom_req_handler_t {
h2o_handler_t super;
HttpServer* http_server;
std::string api_auth_key_sent;
};
struct h2o_custom_generator_t {

View File

@ -176,6 +176,15 @@ bool AuthManager::authenticate(const std::string& action,
return (num_keys_matched == collection_keys.size());
}
bool AuthManager::regexp_match(const std::string& value, const std::string& regexp) {
try {
return std::regex_match (value, std::regex(regexp));
} catch(const std::exception& e) {
LOG(ERROR) << "Error while matching regexp " << regexp << " against value " << value;
return false;
}
}
bool AuthManager::auth_against_key(const std::string& req_collection, const std::string& action,
const api_key_t& api_key, const bool search_only) const {
@ -221,7 +230,7 @@ bool AuthManager::auth_against_key(const std::string& req_collection, const std:
for(const std::string& allowed_collection: api_key.collections) {
if(allowed_collection == "*" || (allowed_collection == req_collection) || req_collection.empty() ||
std::regex_match (req_collection, std::regex(allowed_collection))) {
regexp_match(req_collection, allowed_collection)) {
coll_allowed = true;
break;
}

View File

@ -278,7 +278,6 @@ void HttpServer::on_res_generator_dispose(void *self) {
}
// without this, warning about memory allocated by std::string leaking happens
std::string().swap(custom_generator->h2o_handler->api_auth_key_sent);
delete custom_generator;
}
@ -398,14 +397,13 @@ int HttpServer::catch_all_handler(h2o_handler_t *_h2o_handler, h2o_req_t *req) {
// Extract auth key from header. If that does not exist, look for a GET parameter.
ssize_t auth_header_cursor = h2o_find_header_by_str(&req->headers, http_req::AUTH_HEADER, strlen(http_req::AUTH_HEADER), -1);
std::string api_auth_key_sent;
if(auth_header_cursor != -1) {
h2o_iovec_t & slot = req->headers.entries[auth_header_cursor].value;
const std::string api_auth_key_sent = std::string(slot.base, slot.len);
// NOTE: directly using `h2o_handler->api_auth_key_sent` without an intermediate string causes memory errors
h2o_handler->api_auth_key_sent = api_auth_key_sent;
api_auth_key_sent = std::string(slot.base, slot.len);
} else if(query_map.count(http_req::AUTH_HEADER) != 0) {
h2o_handler->api_auth_key_sent = query_map[http_req::AUTH_HEADER];
api_auth_key_sent = query_map[http_req::AUTH_HEADER];
}
route_path *rpath = nullptr;
@ -460,7 +458,7 @@ int HttpServer::catch_all_handler(h2o_handler_t *_h2o_handler, h2o_req_t *req) {
// multi_search needs to be handled later because the API key could be part of request body and
// the whole request body might not be available right now.
bool authenticated = h2o_handler->http_server->auth_handler(query_map, embedded_params_vec, body, *rpath,
h2o_handler->api_auth_key_sent);
api_auth_key_sent);
if(!authenticated) {
std::string message = std::string("{\"message\": \"Forbidden - a valid `") + http_req::AUTH_HEADER +
"` header must be sent.\"}";
@ -469,8 +467,8 @@ int HttpServer::catch_all_handler(h2o_handler_t *_h2o_handler, h2o_req_t *req) {
}
std::shared_ptr<http_req> request = std::make_shared<http_req>(req, rpath->http_method, path_without_query,
route_hash, query_map, embedded_params_vec, body,
client_ip);
route_hash, query_map, embedded_params_vec,
api_auth_key_sent, body, client_ip);
// add custom generator with a dispose function for cleaning up resources
h2o_custom_generator_t* custom_gen = new h2o_custom_generator_t;
@ -656,7 +654,7 @@ int HttpServer::process_request(const std::shared_ptr<http_req>& request, const
if(root_resource == "multi_search") {
// We can authenticate only when the full request body is available
bool authenticated = handler->http_server->auth_handler(request->params, request->embedded_params_vec,
request->body, *rpath, handler->api_auth_key_sent);
request->body, *rpath, request->api_auth_key);
if(!authenticated) {
std::string message = std::string("{\"message\": \"Forbidden - a valid `") + http_req::AUTH_HEADER +
"` header must be sent.\"}";

View File

@ -251,6 +251,13 @@ TEST_F(AuthManagerTest, VerifyAuthentication) {
{collection_key_t("collection1", coll_a_key.value),
collection_key_t("collectionB", coll_b_key.value)},
sparams, embedded_params));
// bad collection allow regexp
api_key_t coll_c_key = api_key_t("coll_c", "one action key", {"documents:search"}, {"*coll_c"}, FUTURE_TS);
auth_manager.create_key(coll_c_key);
ASSERT_FALSE(auth_manager.authenticate("documents:search",
{collection_key_t("coll_c", coll_c_key.value),},
sparams, embedded_params));
}
TEST_F(AuthManagerTest, GenerationOfAPIAction) {