mirror of
https://github.com/typesense/typesense.git
synced 2025-05-19 13:12:22 +08:00
Merge branch 'main' into v0.24-changes
This commit is contained in:
commit
f189ed7a31
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.\"}";
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user