fix(user-settings): improve route matching for keys containing slashes (#32382)
Signed-off-by: Teijo Mursu <zcmander@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-user-settings-backend': patch
|
||||
---
|
||||
|
||||
Resolves an issue where user setting keys containing slashes returned 404 not found.
|
||||
@@ -74,6 +74,30 @@ describe('createRouter', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns ok for keys with forward slashes', async () => {
|
||||
const setting = {
|
||||
bucket: 'my-bucket',
|
||||
key: 'my-key/with/slashes',
|
||||
value: 'a',
|
||||
};
|
||||
|
||||
userSettingsStore.get.mockResolvedValue(setting);
|
||||
|
||||
const responses = await request(app).get(
|
||||
'/buckets/my-bucket/keys/my-key/with/slashes',
|
||||
);
|
||||
|
||||
expect(responses.status).toEqual(200);
|
||||
expect(responses.body).toEqual(setting);
|
||||
|
||||
expect(userSettingsStore.get).toHaveBeenCalledTimes(1);
|
||||
expect(userSettingsStore.get).toHaveBeenCalledWith({
|
||||
userEntityRef: mockUserRef,
|
||||
bucket: 'my-bucket',
|
||||
key: 'my-key/with/slashes',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if the Authorization header is missing', async () => {
|
||||
const responses = await request(app)
|
||||
.get('/buckets/my-bucket/keys/my-key')
|
||||
@@ -107,6 +131,28 @@ describe('createRouter', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns ok for keys with forward slashes', async () => {
|
||||
userSettingsStore.delete.mockResolvedValue();
|
||||
|
||||
const responses = await request(app).delete(
|
||||
'/buckets/my-bucket/keys/my-key/with/slashes',
|
||||
);
|
||||
|
||||
expect(responses.status).toEqual(204);
|
||||
|
||||
expect(userSettingsStore.delete).toHaveBeenCalledTimes(1);
|
||||
expect(userSettingsStore.delete).toHaveBeenCalledWith({
|
||||
userEntityRef: mockUserRef,
|
||||
bucket: 'my-bucket',
|
||||
key: 'my-key/with/slashes',
|
||||
});
|
||||
expect(signalService.publish).toHaveBeenCalledWith({
|
||||
recipients: { type: 'user', entityRef: mockUserRef },
|
||||
channel: `user-settings`,
|
||||
message: { type: 'key-deleted', key: 'my-key/with/slashes' },
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if the Authorization header is missing', async () => {
|
||||
const responses = await request(app)
|
||||
.delete('/buckets/my-bucket/keys/my-key')
|
||||
@@ -151,6 +197,26 @@ describe('createRouter', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns ok for keys with forward slashes', async () => {
|
||||
const setting = {
|
||||
bucket: 'my-bucket',
|
||||
key: 'my-key/with/slashes',
|
||||
value: 'a',
|
||||
};
|
||||
|
||||
userSettingsStore.set.mockResolvedValue();
|
||||
userSettingsStore.get.mockResolvedValue(setting);
|
||||
|
||||
const responses = await request(app)
|
||||
.put('/buckets/my-bucket/keys/my-key/with/slashes')
|
||||
.send({ value: 'a' });
|
||||
|
||||
expect(responses.status).toEqual(200);
|
||||
expect(responses.body).toEqual(setting);
|
||||
|
||||
expect(userSettingsStore.set).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('returns an error if the value is not given', async () => {
|
||||
const responses = await request(app)
|
||||
.put('/buckets/my-bucket/keys/my-key')
|
||||
|
||||
@@ -41,7 +41,7 @@ export async function createRouter(options: {
|
||||
};
|
||||
|
||||
// get a single value
|
||||
router.get('/buckets/:bucket/keys/:key', async (req, res) => {
|
||||
router.get('/buckets/:bucket/keys/:key(*)', async (req, res) => {
|
||||
const userEntityRef = await getUserEntityRef(req);
|
||||
const { bucket, key } = req.params;
|
||||
|
||||
@@ -55,7 +55,7 @@ export async function createRouter(options: {
|
||||
});
|
||||
|
||||
// set a single value
|
||||
router.put('/buckets/:bucket/keys/:key', async (req, res) => {
|
||||
router.put('/buckets/:bucket/keys/:key(*)', async (req, res) => {
|
||||
const userEntityRef = await getUserEntityRef(req);
|
||||
const { bucket, key } = req.params;
|
||||
const { value } = req.body;
|
||||
@@ -87,8 +87,8 @@ export async function createRouter(options: {
|
||||
res.json(setting);
|
||||
});
|
||||
|
||||
// get a single value
|
||||
router.delete('/buckets/:bucket/keys/:key', async (req, res) => {
|
||||
// delete a single value
|
||||
router.delete('/buckets/:bucket/keys/:key(*)', async (req, res) => {
|
||||
const userEntityRef = await getUserEntityRef(req);
|
||||
const { bucket, key } = req.params;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user