revert rls on old tables

This commit is contained in:
Hongbo Wu 2023-09-21 14:45:59 +08:00
parent d5c247a98d
commit 9e5196406e
15 changed files with 179 additions and 41 deletions

View file

@ -49,11 +49,12 @@ export const labelRepository = entityManager.getRepository(Label).extend({
.getOne()
},
findByNames(names: string[]) {
findByNames(names: string[], userId: string) {
return this.createQueryBuilder()
.where('LOWER(name) IN (:...names)', {
names: names.map((n) => n.toLowerCase()),
})
.andWhere('user_id = :userId', { userId })
.getMany()
},

View file

@ -794,7 +794,7 @@ export const bulkActionResolver = authorized<
return { errorCodes: [BulkActionErrorCode.BadRequest] }
}
labels = await findLabelsByIds(labelIds)
labels = await findLabelsByIds(labelIds, uid)
}
// parse query

View file

@ -50,6 +50,9 @@ export const labelsResolver = authorized<LabelsSuccess, LabelsError>(
const labels = await authTrx(async (tx) => {
return tx.withRepository(labelRepository).find({
where: {
user: { id: uid },
},
order: {
position: 'ASC',
},

View file

@ -20,10 +20,13 @@ import { sendEmail } from '../../utils/sendEmail'
export const recentEmailsResolver = authorized<
RecentEmailsSuccess,
RecentEmailsError
>(async (_, __, { authTrx, log }) => {
>(async (_, __, { authTrx, log, uid }) => {
try {
const recentEmails = await authTrx((t) =>
t.getRepository(ReceivedEmail).find({
where: {
user: { id: uid },
},
order: { createdAt: 'DESC' },
take: 20,
})
@ -50,6 +53,7 @@ export const markEmailAsItemResolver = authorized<
const recentEmail = await authTrx((t) =>
t.getRepository(ReceivedEmail).findOneBy({
id: recentEmailId,
user: { id: uid },
type: 'non-article',
})
)
@ -64,6 +68,7 @@ export const markEmailAsItemResolver = authorized<
const newsletterEmail = await authTrx((t) =>
t.getRepository(NewsletterEmail).findOne({
where: {
user: { id: uid },
address: ILike(recentEmail.to),
},
relations: ['user'],

View file

@ -28,13 +28,11 @@ export const setDeviceTokenResolver = authorized<
SetDeviceTokenSuccess,
SetDeviceTokenError,
MutationSetDeviceTokenArgs
>(async (_parent, { input }, { claims: { uid }, log }) => {
log.info('setDeviceTokenResolver', input)
>(async (_parent, { input }, { uid, log }) => {
const { id, token } = input
if (!id && !token) {
log.info('id or token is required')
log.error('id or token is required')
return {
errorCodes: [SetDeviceTokenErrorCode.BadRequest],
@ -44,7 +42,7 @@ export const setDeviceTokenResolver = authorized<
try {
// when token is null, we are deleting it
if (!token && id) {
const deviceToken = await findDeviceTokenById(id)
const deviceToken = await findDeviceTokenById(id, uid)
if (!deviceToken) {
log.error('device token not found', id)
@ -107,7 +105,7 @@ export const setDeviceTokenResolver = authorized<
token
) {
// duplicate token
const deviceToken = await findDeviceTokenByToken(token)
const deviceToken = await findDeviceTokenByToken(token, uid)
if (!deviceToken) {
return {

View file

@ -18,7 +18,10 @@ export const findApiKeys = async (
'createdAt',
'usedAt',
],
where,
where: {
...where,
user: { id: userId },
},
order: {
usedAt: { direction: 'DESC', nulls: 'last' },
createdAt: 'DESC',

View file

@ -45,7 +45,11 @@ export const findIntegration = async (
userId: string
) => {
return authTrx(
async (t) => t.getRepository(Integration).findOneBy(where),
async (t) =>
t.getRepository(Integration).findOneBy({
...where,
user: { id: userId },
}),
undefined,
userId
)
@ -56,7 +60,11 @@ export const findIntegrations = async (
where?: FindOptionsWhere<Integration> | FindOptionsWhere<Integration>[]
) => {
return authTrx(
async (t) => t.getRepository(Integration).find({ where }),
async (t) =>
t.getRepository(Integration).findBy({
...where,
user: { id: userId },
}),
undefined,
userId
)

View file

@ -31,7 +31,8 @@ export const findOrCreateLabels = async (
const labelRepo = tx.withRepository(labelRepository)
// find existing labels
const labelEntities = await labelRepo.findByNames(
labels.map((l) => l.name)
labels.map((l) => l.name),
userId
)
const existingLabelsInLowerCase = labelEntities.map((l) =>
@ -99,7 +100,7 @@ export const addLabelsToLibraryItem = async (
async (tx) => {
const libraryItem = await tx
.withRepository(libraryItemRepository)
.findOneByOrFail({ id: libraryItemId })
.findOneByOrFail({ id: libraryItemId, user: { id: userId } })
if (libraryItem.labels) {
labels.push(...libraryItem.labels)
@ -156,12 +157,20 @@ export const saveLabelsInHighlight = async (
)
}
export const findLabelsByIds = async (ids: string[]): Promise<Label[]> => {
return authTrx(async (tx) => {
return tx.withRepository(labelRepository).findBy({
id: In(ids),
})
})
export const findLabelsByIds = async (
ids: string[],
userId: string
): Promise<Label[]> => {
return authTrx(
async (tx) => {
return tx.withRepository(labelRepository).findBy({
id: In(ids),
user: { id: userId },
})
},
undefined,
userId
)
}
export const createLabel = async (
@ -219,7 +228,10 @@ export const findLabelsByUserId = async (userId: string): Promise<Label[]> => {
export const findLabelById = async (id: string, userId: string) => {
return authTrx(
async (tx) => tx.withRepository(labelRepository).findOneBy({ id }),
async (tx) =>
tx
.withRepository(labelRepository)
.findOneBy({ id, user: { id: userId } }),
undefined,
userId
)

View file

@ -32,23 +32,27 @@ export const updateReceivedEmail = async (
userId: string
) => {
return authTrx(
(t) => t.getRepository(ReceivedEmail).update(id, { type }),
(t) =>
t
.getRepository(ReceivedEmail)
.update({ id, user: { id: userId } }, { type }),
undefined,
userId
)
}
export const deleteReceivedEmail = async (id: string, userId?: string) => {
export const deleteReceivedEmail = async (id: string, userId: string) => {
return authTrx(
(t) => t.getRepository(ReceivedEmail).delete(id),
(t) => t.getRepository(ReceivedEmail).delete({ id, user: { id: userId } }),
undefined,
userId
)
}
export const findReceivedEmailById = async (id: string, userId?: string) => {
export const findReceivedEmailById = async (id: string, userId: string) => {
return authTrx(
(t) => t.getRepository(ReceivedEmail).findOneBy({ id }),
(t) =>
t.getRepository(ReceivedEmail).findOneBy({ id, user: { id: userId } }),
undefined,
userId
)

View file

@ -13,6 +13,7 @@ export const createRule = async (
): Promise<Rule> => {
const existingRule = await authTrx((t) =>
t.getRepository(Rule).findOneBy({
user: { id: userId },
name: ILike(rule.name),
})
)
@ -32,11 +33,11 @@ export const createRule = async (
)
}
export const deleteRule = async (id: string, userId?: string) => {
export const deleteRule = async (id: string, userId: string) => {
return authTrx(
async (t) => {
const repo = t.getRepository(Rule)
const rule = await repo.findOneByOrFail({ id })
const rule = await repo.findOneByOrFail({ id, user: { id: userId } })
await repo.delete(id)
return rule
},

View file

@ -6,19 +6,28 @@ import { analytics } from '../utils/analytics'
export const findDeviceTokenById = async (
id: string,
userId?: string
userId: string
): Promise<UserDeviceToken | null> => {
return authTrx(
(t) => t.getRepository(UserDeviceToken).findOneBy({ id }),
(t) =>
t.getRepository(UserDeviceToken).findOneBy({ id, user: { id: userId } }),
undefined,
userId
)
}
export const findDeviceTokenByToken = async (
token: string
token: string,
userId: string
): Promise<UserDeviceToken | null> => {
return authTrx((t) => t.getRepository(UserDeviceToken).findOneBy({ token }))
return authTrx(
(t) =>
t
.getRepository(UserDeviceToken)
.findOneBy({ token, user: { id: userId } }),
undefined,
userId
)
}
export const findDeviceTokensByUserId = async (
@ -70,7 +79,9 @@ export const deleteDeviceToken = async (
})
return authTrx(async (t) => {
const result = await t.getRepository(UserDeviceToken).delete(id)
const result = await t
.getRepository(UserDeviceToken)
.delete({ id, user: { id: userId } })
return !!result.affected
})

View file

@ -26,7 +26,7 @@ export const createWebhook = async (
)
}
export const findWebhooks = async (userId?: string) => {
export const findWebhooks = async (userId: string) => {
return authTrx(
(tx) => tx.getRepository(Webhook).findBy({ user: { id: userId } }),
undefined,
@ -34,19 +34,19 @@ export const findWebhooks = async (userId?: string) => {
)
}
export const findWebhookById = async (id: string, userId?: string) => {
export const findWebhookById = async (id: string, userId: string) => {
return authTrx(
(tx) => tx.getRepository(Webhook).findOneBy({ id }),
(tx) => tx.getRepository(Webhook).findOneBy({ id, user: { id: userId } }),
undefined,
userId
)
}
export const deleteWebhook = async (id: string, userId?: string) => {
export const deleteWebhook = async (id: string, userId: string) => {
return authTrx(
async (tx) => {
const repo = tx.getRepository(Webhook)
const webhook = await repo.findOneByOrFail({ id })
const webhook = await repo.findOneByOrFail({ id, user: { id: userId } })
await repo.delete(id)
return webhook
},

View file

@ -3,9 +3,12 @@ import 'mocha'
import { User } from '../../src/entity/user'
import { UserDeviceToken } from '../../src/entity/user_device_tokens'
import { SetDeviceTokenErrorCode } from '../../src/generated/graphql'
import { getRepository } from '../../src/repository'
import { deleteUser } from '../../src/services/user'
import { createDeviceToken, deleteDeviceTokens, findDeviceTokenById } from '../../src/services/user_device_tokens'
import {
createDeviceToken,
deleteDeviceTokens,
findDeviceTokenById,
} from '../../src/services/user_device_tokens'
import { createTestDeviceToken, createTestUser } from '../db'
import { generateFakeUuid, graphqlRequest, request } from '../util'
@ -76,7 +79,8 @@ describe('Device tokens API', () => {
it('responds with status code 200 and deletes the token', async () => {
const response = await graphqlRequest(query, authToken).expect(200)
const deviceToken = await findDeviceTokenById(
response.body.data.setDeviceToken.deviceToken.id
response.body.data.setDeviceToken.deviceToken.id,
user.id
)
expect(deviceToken).to.be.null
})

View file

@ -0,0 +1,38 @@
-- Type: DO
-- Name: revert_rls
-- Description: Revert rls on rows
BEGIN;
ALTER TABLE omnivore.filters DISABLE ROW LEVEL SECURITY;
DROP POLICY filters_policy on omnivore.filters;
ALTER TABLE omnivore.integrations DISABLE ROW LEVEL SECURITY;
DROP POLICY integrations_policy on omnivore.integrations;
DROP POLICY labels_policy on omnivore.labels;
CREATE POLICY read_labels on omnivore.labels
FOR SELECT TO omnivore_user
USING (true);
CREATE POLICY create_labels on omnivore.labels
FOR INSERT TO omnivore_user
WITH CHECK (true);
ALTER TABLE omnivore.received_emails DISABLE ROW LEVEL SECURITY;
DROP POLICY received_emails_policy on omnivore.received_emails;
ALTER TABLE omnivore.rules DISABLE ROW LEVEL SECURITY;
DROP POLICY rules_policy on omnivore.rules;
ALTER TABLE omnivore.webhooks DISABLE ROW LEVEL SECURITY;
DROP POLICY webhooks_policy on omnivore.webhooks;
DROP POLICY user_device_tokens_policy on omnivore.user_device_tokens;
CREATE POLICY read_user_device_tokens on omnivore.user_device_tokens
FOR SELECT TO omnivore_user
USING (true);
CREATE POLICY create_user_device_tokens on omnivore.user_device_tokens
FOR INSERT TO omnivore_user
WITH CHECK (true);
COMMIT;

View file

@ -0,0 +1,50 @@
-- Type: UNDO
-- Name: revert_rls
-- Description: Revert rls on rows
BEGIN;
ALTER TABLE omnivore.filters ENABLE ROW LEVEL SECURITY;
CREATE POLICY filters_policy on omnivore.filters
USING (user_id = omnivore.get_current_user_id())
WITH CHECK (user_id = omnivore.get_current_user_id());
GRANT SELECT, INSERT, UPDATE, DELETE ON omnivore.filters TO omnivore_user;
ALTER TABLE omnivore.integrations ENABLE ROW LEVEL SECURITY;
CREATE POLICY integrations_policy on omnivore.integrations
USING (user_id = omnivore.get_current_user_id())
WITH CHECK (user_id = omnivore.get_current_user_id());
GRANT SELECT, INSERT, UPDATE, DELETE ON omnivore.integrations TO omnivore_user;
DROP POLICY read_labels ON omnivore.labels;
DROP POLICY create_labels ON omnivore.labels;
CREATE POLICY labels_policy on omnivore.labels
USING (user_id = omnivore.get_current_user_id())
WITH CHECK (user_id = omnivore.get_current_user_id());
ALTER TABLE omnivore.received_emails ENABLE ROW LEVEL SECURITY;
CREATE POLICY received_emails_policy on omnivore.received_emails
USING (user_id = omnivore.get_current_user_id())
WITH CHECK (user_id = omnivore.get_current_user_id());
GRANT SELECT, INSERT, UPDATE ON omnivore.received_emails TO omnivore_user;
ALTER TABLE omnivore.rules ENABLE ROW LEVEL SECURITY;
CREATE POLICY rules_policy on omnivore.rules
USING (user_id = omnivore.get_current_user_id())
WITH CHECK (user_id = omnivore.get_current_user_id());
GRANT SELECT, INSERT, UPDATE, DELETE ON omnivore.rules TO omnivore_user;
ALTER TABLE omnivore.webhooks ENABLE ROW LEVEL SECURITY;
CREATE POLICY webhooks_policy on omnivore.webhooks
USING (user_id = omnivore.get_current_user_id())
WITH CHECK (user_id = omnivore.get_current_user_id());
GRANT SELECT, INSERT, UPDATE, DELETE ON omnivore.webhooks TO omnivore_user;
DROP POLICY read_user_device_tokens ON omnivore.user_device_tokens;
DROP POLICY create_user_device_tokens ON omnivore.user_device_tokens;
CREATE POLICY user_device_tokens_policy on omnivore.user_device_tokens
USING (user_id = omnivore.get_current_user_id())
WITH CHECK (user_id = omnivore.get_current_user_id());
GRANT SELECT, INSERT, DELETE ON omnivore.user_device_tokens TO omnivore_user;
COMMIT;