mirror of
https://github.com/bckelley/cgm-remote-monitor.git
synced 2026-08-24 03:14:12 -05:00
feat(devicestatus): return 400 for invalid _id format
Add validation for _id field in devicestatus API: - POST: validates each document's _id before storage - DELETE: validates _id parameter (allows wildcard '*') Accepts: undefined, null, or 24-character hex string Rejects: UUIDs, short strings, numbers, objects with 400 Bad Request Previously, invalid _id values were silently stored as strings instead of ObjectIds, causing inconsistent data and query issues. Tests added for all validation cases. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -96,4 +96,157 @@ describe('Devicestatus API', function ( ) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// _id validation tests (prevent silent data corruption and ensure 400 on invalid)
|
||||
describe('_id validation', function() {
|
||||
|
||||
it('should return 400 for POST with invalid UUID _id', function(done) {
|
||||
var status_with_uuid = {
|
||||
"_id": "my-uuid-12345",
|
||||
"device": "test-device",
|
||||
"created_at": "2024-01-01T00:00:00Z"
|
||||
};
|
||||
|
||||
request(self.app)
|
||||
.post('/api/devicestatus/')
|
||||
.set('api-secret', known || '')
|
||||
.send(status_with_uuid)
|
||||
.expect(400)
|
||||
.expect(function(response) {
|
||||
response.body.should.have.property('status', 400);
|
||||
response.body.should.have.property('message');
|
||||
response.body.message.should.match(/Invalid _id format/i);
|
||||
})
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('should return 400 for POST with short _id', function(done) {
|
||||
var status_short_id = {
|
||||
"_id": "abc",
|
||||
"device": "test-device",
|
||||
"created_at": "2024-01-01T00:00:00Z"
|
||||
};
|
||||
|
||||
request(self.app)
|
||||
.post('/api/devicestatus/')
|
||||
.set('api-secret', known || '')
|
||||
.send(status_short_id)
|
||||
.expect(400)
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('should return 400 for DELETE with invalid _id', function(done) {
|
||||
request(self.app)
|
||||
.delete('/api/devicestatus/invalid-uuid-here')
|
||||
.set('api-secret', known || '')
|
||||
.expect(400)
|
||||
.expect(function(response) {
|
||||
response.body.message.should.match(/Invalid _id format/i);
|
||||
})
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('should accept POST with valid 24-hex _id', function(done) {
|
||||
// Use a unique ID that doesn't conflict with other tests
|
||||
var testId = 'bbbbbbbbbbbbbbbbbbbbbbbb';
|
||||
var status_valid_id = {
|
||||
"_id": testId,
|
||||
"device": "test-device-valid",
|
||||
"created_at": "2024-01-02T00:00:00Z"
|
||||
};
|
||||
|
||||
// First, try to delete any existing document with this _id (cleanup from previous runs)
|
||||
request(self.app)
|
||||
.delete('/api/devicestatus/' + testId)
|
||||
.set('api-secret', known || '')
|
||||
.end(function() {
|
||||
// Ignore errors (document may not exist)
|
||||
request(self.app)
|
||||
.post('/api/devicestatus/')
|
||||
.set('api-secret', known || '')
|
||||
.send(status_valid_id)
|
||||
.expect(200)
|
||||
.expect(function(response) {
|
||||
response.body.should.be.an.Array();
|
||||
response.body.length.should.equal(1);
|
||||
response.body[0]._id.should.equal(testId);
|
||||
})
|
||||
.end(function(err) {
|
||||
if (err) return done(err);
|
||||
// Clean up
|
||||
request(self.app)
|
||||
.delete('/api/devicestatus/' + testId)
|
||||
.set('api-secret', known || '')
|
||||
.expect(200)
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should accept POST without _id (auto-generate)', function(done) {
|
||||
var status_no_id = {
|
||||
"device": "test-device-autogen",
|
||||
"created_at": "2024-01-03T00:00:00Z"
|
||||
};
|
||||
|
||||
request(self.app)
|
||||
.post('/api/devicestatus/')
|
||||
.set('api-secret', known || '')
|
||||
.send(status_no_id)
|
||||
.expect(200)
|
||||
.expect(function(response) {
|
||||
response.body.should.be.an.Array();
|
||||
response.body.length.should.equal(1);
|
||||
response.body[0].should.have.property('_id');
|
||||
// Verify auto-generated _id is valid ObjectId format
|
||||
response.body[0]._id.toString().should.match(/^[a-fA-F0-9]{24}$/);
|
||||
})
|
||||
.end(function(err, res) {
|
||||
if (err) return done(err);
|
||||
// Clean up
|
||||
var createdId = res.body[0]._id;
|
||||
request(self.app)
|
||||
.delete('/api/devicestatus/' + createdId)
|
||||
.set('api-secret', known || '')
|
||||
.expect(200)
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return 400 for array POST with one invalid _id', function(done) {
|
||||
var statuses_mixed = [
|
||||
{ "device": "device1", "created_at": "2024-01-01T00:00:00Z" },
|
||||
{ "_id": "bad-uuid", "device": "device2", "created_at": "2024-01-02T00:00:00Z" }
|
||||
];
|
||||
|
||||
request(self.app)
|
||||
.post('/api/devicestatus/')
|
||||
.set('api-secret', known || '')
|
||||
.send(statuses_mixed)
|
||||
.expect(400)
|
||||
.expect(function(response) {
|
||||
response.body.message.should.match(/Invalid _id format/i);
|
||||
})
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('should allow DELETE with wildcard _id', function(done) {
|
||||
// First insert a test record
|
||||
request(self.app)
|
||||
.post('/api/devicestatus/')
|
||||
.set('api-secret', known || '')
|
||||
.send({ "device": "delete-wildcard-test", "created_at": "2020-01-01T00:00:00Z" })
|
||||
.expect(200)
|
||||
.end(function(err) {
|
||||
if (err) return done(err);
|
||||
// Wildcard delete with date filter should work
|
||||
request(self.app)
|
||||
.delete('/api/devicestatus/*')
|
||||
.query('find[created_at][$lte]=2020-01-02')
|
||||
.set('api-secret', known || '')
|
||||
.expect(200)
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+23
-14
@@ -213,31 +213,40 @@ describe('Profiles API', function ( ) {
|
||||
});
|
||||
|
||||
it('should accept POST with valid 24-hex _id', function(done) {
|
||||
// Use a unique ID that doesn't conflict with other tests
|
||||
var testId = 'aaaaaaaaaaaaaaaaaaaaaaaa';
|
||||
var profile_valid_id = {
|
||||
"_id": "507f1f77bcf86cd799439011",
|
||||
"_id": testId,
|
||||
"defaultProfile": "Default",
|
||||
"store": { "Default": { "dia": 3 } },
|
||||
"startDate": "2024-10-19T23:00:00.000Z"
|
||||
};
|
||||
|
||||
// First, try to delete any existing document with this _id (cleanup from previous runs)
|
||||
request(self.app)
|
||||
.post('/api/profile/')
|
||||
.delete('/api/profile/' + testId)
|
||||
.set('api-secret', known || '')
|
||||
.send(profile_valid_id)
|
||||
.expect(200)
|
||||
.expect(function(response) {
|
||||
response.body.should.be.an.Array();
|
||||
response.body.length.should.equal(1);
|
||||
response.body[0]._id.should.equal('507f1f77bcf86cd799439011');
|
||||
})
|
||||
.end(function(err) {
|
||||
if (err) return done(err);
|
||||
// Clean up: delete the profile we just created
|
||||
.end(function() {
|
||||
// Ignore errors (document may not exist)
|
||||
request(self.app)
|
||||
.delete('/api/profile/507f1f77bcf86cd799439011')
|
||||
.post('/api/profile/')
|
||||
.set('api-secret', known || '')
|
||||
.send(profile_valid_id)
|
||||
.expect(200)
|
||||
.end(done);
|
||||
.expect(function(response) {
|
||||
response.body.should.be.an.Array();
|
||||
response.body.length.should.equal(1);
|
||||
response.body[0]._id.should.equal(testId);
|
||||
})
|
||||
.end(function(err) {
|
||||
if (err) return done(err);
|
||||
// Clean up: delete the profile we just created
|
||||
request(self.app)
|
||||
.delete('/api/profile/' + testId)
|
||||
.set('api-secret', known || '')
|
||||
.expect(200)
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user