Skip to content

Commit fb65850

Browse files
authored
[DAPS-1862] - fix allocation change failure (#1864)
1 parent eba87f5 commit fb65850

File tree

7 files changed

+119
-65
lines changed

7 files changed

+119
-65
lines changed

core/database/foxx/api/authz_router.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,14 @@ router
4545
if (!client) {
4646
throw [error.ERR_PERM_DENIED, "Unknown client: " + req.queryParams.client];
4747
}
48-
let repo = new Repo(req.queryParams.repo);
48+
let repo = Repo.resolveFromPath(req.queryParams.file);
49+
50+
if (repo.id() !== req.queryParams.repo) {
51+
throw [
52+
error.ERR_PERM_DENIED,
53+
"File path does not match repository: " + req.queryParams.file,
54+
];
55+
}
4956
let path_type = repo.pathType(req.queryParams.file);
5057

5158
// If the provided path is not within the repo throw an error

core/database/foxx/api/posix_path.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use strict";
22

3+
const error = require("./lib/error_codes");
34
const path = require("path");
45

56
module.exports = (function () {
@@ -45,5 +46,12 @@ module.exports = (function () {
4546
return components.filter((component) => component !== "");
4647
};
4748

49+
obj.normalizePOSIXPath = function (a_posix_path) {
50+
if (!a_posix_path || typeof a_posix_path !== "string") {
51+
throw [error.ERR_INVALID_PARAM, "Invalid POSIX path"];
52+
}
53+
return path.posix.normalize(a_posix_path);
54+
};
55+
4856
return obj;
4957
})();

core/database/foxx/api/record.js

Lines changed: 51 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -66,23 +66,23 @@ class Record {
6666
/**
6767
* Generates the full path to the record as it should appear in the repository.
6868
*
69-
* @param {object} loc - The location object which specifies the owner of the record.
70-
* @param {string} basePath - The base path where the record is stored.
71-
*
72-
* @returns {string} - the path to the record or null if error
69+
* @param {string} uid - The owner uid (e.g. "u/bob" or "p/myproject")
70+
* @param {string} basePath - The base path of the repository.
71+
* @returns {string|null} - the path to the record or null if error
7372
*/
74-
_pathToRecord(loc, basePath) {
73+
_pathToRecord(uid, basePath) {
7574
const path = basePath.endsWith("/") ? basePath : basePath + "/";
76-
if (loc.uid.charAt(0) == "u") {
77-
return path + "user/" + loc.uid.substr(2) + "/" + this.#key;
78-
} else if (loc.uid.charAt(0) == "p") {
79-
return path + "project/" + loc.uid.substr(2) + "/" + this.#key;
75+
if (uid.charAt(0) === "u") {
76+
return path + "user/" + uid.substr(2) + "/" + this.#key;
77+
} else if (uid.charAt(0) === "p") {
78+
return path + "project/" + uid.substr(2) + "/" + this.#key;
8079
} else {
8180
this.#error = error.ERR_INTERNAL_FAULT;
82-
this.#err_msg = "Provided path does not fit within supported directory ";
83-
this.#err_msg += "structure for repository, no user or project folder has";
84-
this.#err_msg += " been determined for the record.";
85-
console.log(e);
81+
this.#err_msg =
82+
"Provided uid does not fit within supported directory " +
83+
"structure for repository, no user or project folder has " +
84+
"been determined for the record. uid: " +
85+
uid;
8686
return null;
8787
}
8888
}
@@ -174,77 +174,71 @@ class Record {
174174
return !!this.#alloc;
175175
}
176176

177-
/**
178-
* Validates if the provided record path is consistent with the database.
179-
*
180-
* @param {string} a_path - The path to validate.
181-
* @returns {boolean} True if consistent, otherwise false.
182-
*/
183177
isPathConsistent(a_path) {
184-
// This function will populate the this.#loc member and the this.#alloc
185-
// member
186178
if (!this.isManaged()) {
187179
return false;
188180
}
189181

190-
// If there is a new repo we need to check the path there and use that
182+
if (!a_path.startsWith("/")) {
183+
a_path = "/" + a_path;
184+
}
185+
186+
// If record is in flight, only check new location
191187
if (this.#loc.hasOwnProperty("new_repo") && this.#loc.new_repo) {
192-
// Below we get the allocation associated with data item by
193-
// 1. Checking if the data item is in flight, is in the process
194-
// of being moved to a new location or new owner and using that
195-
// oweners id.
196-
// 2. Using the loc.uid parameter if not inflight to get the owner
197-
// id.
188+
const new_uid = this.#loc.new_owner ? this.#loc.new_owner : this.#loc.uid;
198189
const new_alloc = g_db.alloc.firstExample({
199-
_from: this.#loc.new_owner ? this.#loc.new_owner : this.#loc.uid,
190+
_from: new_uid,
200191
_to: this.#loc.new_repo,
201192
});
202193

203-
// If no allocation is found for the item throw an error
204-
// if the paths do not align also throw an error.
205194
if (!new_alloc) {
206195
this.#error = error.ERR_PERM_DENIED;
207196
this.#err_msg =
208-
"Permission denied, '" + this.#key + "' is not part of an allocation '";
197+
"Permission denied, '" + this.#key + "' is not part of an allocation'";
209198
return false;
210199
}
211200

212-
this.#repo = g_db._document(this.#loc.new_repo);
213-
214-
if (!this.#repo) {
201+
const new_repo = g_db._document(this.#loc.new_repo);
202+
if (!new_repo) {
215203
this.#error = error.ERR_INTERNAL_FAULT;
216204
this.#err_msg =
217-
"Unable to find repo that record is meant to be allocated too, '" +
205+
"Unable to find repo '" +
218206
this.#loc.new_repo +
219-
"' record '" +
220-
this.#data_id;
207+
"' for record '" +
208+
this.#data_id +
209+
"'";
221210
return false;
222211
}
223212

224-
// If path is missing the starting "/" add it back in
225-
if (!a_path.startsWith("/") && this.#repo.path.startsWith("/")) {
226-
a_path = "/" + a_path;
213+
let new_path = this._pathToRecord(new_uid, new_repo.path);
214+
if (new_path === a_path) {
215+
return true;
227216
}
228217

229-
let stored_path = this._pathToRecord(this.#loc, this.#repo.path);
230-
231-
if (!this._comparePaths(stored_path, a_path)) {
232-
return false;
233-
}
234-
} else {
235-
this.#repo = g_db._document(this.#loc._to);
218+
this.#error = error.ERR_PERM_DENIED;
219+
this.#err_msg =
220+
"Record path is not consistent with repo. Expected: " +
221+
new_path +
222+
" but got: " +
223+
a_path;
224+
return false;
225+
}
236226

237-
if (!a_path.startsWith("/") && this.#repo.path.startsWith("/")) {
238-
a_path = "/" + a_path;
239-
}
240-
let stored_path = this._pathToRecord(this.#loc, this.#repo.path);
227+
// No in-flight move — check current location
228+
this.#repo = g_db._document(this.#loc._to);
229+
let current_path = this._pathToRecord(this.#loc.uid, this.#repo.path);
241230

242-
// If there is no new repo check that the paths align
243-
if (!this._comparePaths(stored_path, a_path)) {
244-
return false;
245-
}
231+
if (current_path === a_path) {
232+
return true;
246233
}
247-
return true;
234+
235+
this.#error = error.ERR_PERM_DENIED;
236+
this.#err_msg =
237+
"Record path is not consistent with repo. Expected: " +
238+
current_path +
239+
" but got: " +
240+
a_path;
241+
return false;
248242
}
249243
}
250244

core/database/foxx/api/repo.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,40 @@ class Repo {
185185

186186
return PathType.UNKNOWN;
187187
}
188+
189+
static resolveFromPath(file_path) {
190+
var canonical = pathModule.normalizePOSIXPath(file_path);
191+
192+
if (canonical !== file_path) {
193+
throw [error.ERR_PERM_DENIED, "Path contains invalid sequences: " + file_path];
194+
}
195+
196+
var repos = g_db.repo.all().toArray();
197+
var best_match = null;
198+
var best_length = 0;
199+
200+
for (var i = 0; i < repos.length; i++) {
201+
var repo_path = repos[i].path;
202+
if (repo_path.charAt(repo_path.length - 1) !== "/") {
203+
repo_path += "/";
204+
}
205+
if (canonical.indexOf(repo_path) === 0 || canonical === repo_path.slice(0, -1)) {
206+
if (repo_path.length > best_length) {
207+
best_match = repos[i];
208+
best_length = repo_path.length;
209+
}
210+
}
211+
}
212+
213+
if (!best_match) {
214+
throw [
215+
error.ERR_PERM_DENIED,
216+
"File path does not match any known repository: " + file_path,
217+
];
218+
}
219+
220+
return new Repo(best_match._id);
221+
}
188222
}
189223

190224
module.exports = { Repo, PathType };

core/database/foxx/api/tasks.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -892,14 +892,20 @@ var tasks_func = (function () {
892892
//console.log("taskRunRecAllocChg - do xfr");
893893
// Transfer data step
894894

895-
var tokens = g_lib.getAccessToken(a_task.client);
895+
const token_doc = new UserToken({
896+
user_id: a_task.client,
897+
}).get_token();
898+
var tokens = UserToken.formatUserTokenForTransferTask(token_doc);
899+
const extra_token_format = UserToken.formatUserToken(false, token_doc, false);
896900
params = {
897901
uid: a_task.client,
898902
type: a_task.type,
899903
encrypt: state.encrypt,
900904
acc_tok: tokens.acc_tok,
901905
ref_tok: tokens.ref_tok,
902906
acc_tok_exp_in: tokens.acc_tok_exp_in,
907+
token_type: extra_token_format.token_type,
908+
scopes: extra_token_format.scopes,
903909
};
904910
params = Object.assign(params, xfr);
905911
reply = {
@@ -1276,15 +1282,20 @@ var tasks_func = (function () {
12761282
case 1:
12771283
//console.log("taskRunRecOwnerChg - do xfr");
12781284
// Transfer data step
1279-
1280-
var tokens = g_lib.getAccessToken(a_task.client);
1285+
const token_doc = new UserToken({
1286+
user_id: a_task.client,
1287+
}).get_token();
1288+
var tokens = UserToken.formatUserTokenForTransferTask(token_doc);
1289+
const extra_token_format = UserToken.formatUserToken(false, token_doc, false);
12811290
params = {
12821291
uid: a_task.client,
12831292
type: a_task.type,
12841293
encrypt: state.encrypt,
12851294
acc_tok: tokens.acc_tok,
12861295
ref_tok: tokens.ref_tok,
12871296
acc_tok_exp_in: tokens.acc_tok_exp_in,
1297+
token_type: extra_token_format.token_type,
1298+
scopes: extra_token_format.scopes,
12881299
};
12891300
params = Object.assign(params, xfr);
12901301
reply = {

core/database/foxx/tests/record.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ describe("Record Class", () => {
237237
const valid_key = "1127";
238238
const key_id = "d/" + valid_key;
239239
const owner_id = "u/john";
240-
const repo_id = "repo/orange-at-com";
240+
const repo_id = "repo/orange-at-org";
241241
const new_repo_id = "repo/watermelon-at-org";
242242

243243
// Create nodes

web/datafed-ws.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2324,9 +2324,9 @@ function sendMessageDirect(a_msg_name, a_client, a_msg_data, a_cb) {
23242324
* as stable message type identifiers.
23252325
*
23262326
* Each map entry stores:
2327-
* - type: the protobufjs Type (for encode/decode of the inner message)
2328-
* - field_name: the envelope oneof field name (e.g. "version_request")
2329-
* - field_id: the envelope field number (used as msg_type in the frame)
2327+
* - type: the protobufjs Type (for encode/decode of the inner message)
2328+
* - field_name: the envelope oneof field name (e.g. "version_request")
2329+
* - field_id: the envelope field number (used as msg_type in the frame)
23302330
*
23312331
* @param {protobuf.Root} root - The loaded protobuf root containing SDMS.Envelope
23322332
*/

0 commit comments

Comments
 (0)