-
-
Notifications
You must be signed in to change notification settings - Fork 76
/
keys.js
174 lines (156 loc) · 4.77 KB
/
keys.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
These examples walk you through key management operations.
See clientInitalization.js for quick instructions on starting the Typesense server.
*/
require("@babel/register");
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Typesense = require("../../../lib/Typesense");
const masterApiKey = "xyz";
const typesense = new Typesense.Client({
nodes: [
{
host: "127.0.0.1",
port: "8108",
protocol: "http",
},
],
apiKey: masterApiKey,
});
// Let's also setup some test data for this example
let schema = {
name: "users",
fields: [
{
name: "company_id",
type: "int32",
facet: false,
},
{
name: "user_name",
type: "string",
facet: false,
},
{
name: "login_count",
type: "int32",
facet: false,
},
{
name: "country",
type: "string",
facet: true,
},
],
default_sorting_field: "company_id",
};
// We have four users, belonging to two companies: 124 and 126
let documents = [
{
company_id: 124,
user_name: "Hilary Bradford",
login_count: 10,
country: "USA",
},
{
company_id: 124,
user_name: "Nile Carty",
login_count: 100,
country: "USA",
},
{
company_id: 126,
user_name: "Tahlia Maxwell",
login_count: 1,
country: "France",
},
{
company_id: 126,
user_name: "Karl Roy",
login_count: 2,
country: "Germany",
},
];
async function runExample() {
try {
// Delete if the collection already exists from a previous example run
await typesense.collections("users").delete();
} catch (error) {
// do nothing
}
try {
// create a collection
await typesense.collections().create(schema);
// Index documents
await Promise.all(
documents.map((document) => {
return typesense.collections("users").documents().create(document);
}),
);
// Generate an API key and restrict it to only allow searches
// You want to use this API Key in the browser instead of the master API Key
let unscopedSearchOnlyApiKeyResponse = await typesense.keys().create({
description: "Search-only key.",
actions: ["documents:search"],
collections: ["*"],
});
console.log(unscopedSearchOnlyApiKeyResponse);
// Save the key returned, since this will be the only time the full API Key is returned, for security purposes
const unscopedSearchOnlyApiKey = unscopedSearchOnlyApiKeyResponse["value"];
// Side note: you can also retrieve metadata of API keys using the ID returned in the above response
unscopedSearchOnlyApiKeyResponse = await typesense
.keys(unscopedSearchOnlyApiKeyResponse["id"])
.retrieve();
console.log(unscopedSearchOnlyApiKeyResponse);
// We'll now use this search-only API key to generate a scoped search API key that can only access documents that have company_id:124
// This is useful when you store multi-tenant data in a single Typesense server, but you only want
// a particular tenant to access their own data. You'd generate one scoped search key per tenant.
// IMPORTANT: scoped search keys should only be generated *server-side*, so as to not leak the unscoped main search key to clients
const scopedSearchOnlyApiKey = typesense
.keys()
.generateScopedSearchKey(unscopedSearchOnlyApiKey, {
filter_by: "company_id:124",
});
console.log(`scopedSearchOnlyApiKey: ${scopedSearchOnlyApiKey}`);
// Now let's search the data using the scoped API Key for company_id:124
// You can do searches with this scopedSearchOnlyKey from the server-side or client-side
const scopedTypesenseClient = new Typesense.Client({
nodes: [
{
host: "127.0.0.1",
port: "8108",
protocol: "http",
},
],
apiKey: scopedSearchOnlyApiKey,
});
let searchResults = [];
searchResults = await scopedTypesenseClient
.collections("users")
.documents()
.search({
q: "Hilary",
query_by: "user_name",
});
console.log(JSON.stringify(searchResults, null, 2));
// Search for a user that exists, but is outside the current key's scope
searchResults = await scopedTypesenseClient
.collections("users")
.documents()
.search({
q: "Maxwell",
query_by: "user_name",
});
console.log(JSON.stringify(searchResults, null, 2)); // Will return empty result set
// Now let's delete the unscopedSearchOnlyKey. You'd want to do this when you need to rotate keys for example.
const results = await typesense
.keys(unscopedSearchOnlyApiKeyResponse["id"])
.delete();
console.log(results);
} catch (error) {
console.log(error);
} finally {
// Cleanup
typesense.collections("users").delete();
}
}
runExample();