Skip to content
This repository has been archived by the owner on Nov 4, 2021. It is now read-only.

Commit

Permalink
Plugins access control (#231)
Browse files Browse the repository at this point in the history
* Use more robust plugin debug descriptions with pluginDigest

* Update plugin60 for is_global

* Update query for plugins currently in force

* Improve pluginDigest format
  • Loading branch information
Twixes committed Mar 5, 2021
1 parent bd014db commit 01537a4
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 27 deletions.
18 changes: 9 additions & 9 deletions src/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { clearError, processError } from './error'
import { getPluginAttachmentRows, getPluginConfigRows, getPluginRows } from './sql'
import { status } from './status'
import { PluginConfig, PluginJsonConfig, PluginsServer, PluginTask, TeamId } from './types'
import { getFileFromArchive } from './utils'
import { getFileFromArchive, pluginDigest } from './utils'
import { createPluginConfigVM } from './vm/vm'

export async function setupPlugins(server: PluginsServer): Promise<void> {
Expand Down Expand Up @@ -119,7 +119,7 @@ async function loadPlugin(server: PluginsServer, pluginConfig: PluginConfig): Pr
await processError(
server,
pluginConfig,
`Could not load posthog config at "${configPath}" for plugin "${plugin.name}"`
`Could not load posthog config at "${configPath}" for ${pluginDigest(plugin)}`
)
return false
}
Expand All @@ -129,7 +129,7 @@ async function loadPlugin(server: PluginsServer, pluginConfig: PluginConfig): Pr
await processError(
server,
pluginConfig,
`No "main" config key or "index.js" file found for plugin "${plugin.name}"`
`No "main" config key or "index.js" file found for ${pluginDigest(plugin)}`
)
return false
}
Expand All @@ -145,7 +145,7 @@ async function loadPlugin(server: PluginsServer, pluginConfig: PluginConfig): Pr

try {
pluginConfig.vm = await createPluginConfigVM(server, pluginConfig, indexJs, libJs)
status.info('🔌', `Loaded local plugin "${plugin.name}" from "${pluginPath}"!`)
status.info('🔌', `Loaded local ${pluginDigest(plugin)} from "${pluginPath}"!`)
await clearError(server, pluginConfig)
return true
} catch (error) {
Expand All @@ -159,7 +159,7 @@ async function loadPlugin(server: PluginsServer, pluginConfig: PluginConfig): Pr
try {
config = JSON.parse(json)
} catch (error) {
await processError(server, pluginConfig, `Can not load plugin.json for plugin "${plugin.name}"`)
await processError(server, pluginConfig, `Can not load plugin.json for ${pluginDigest(plugin)}`)
return false
}
}
Expand All @@ -173,19 +173,19 @@ async function loadPlugin(server: PluginsServer, pluginConfig: PluginConfig): Pr
if (indexJs) {
try {
pluginConfig.vm = await createPluginConfigVM(server, pluginConfig, indexJs, libJs || '')
status.info('🔌', `Loaded plugin "${plugin.name}"!`)
status.info('🔌', `Loaded ${pluginDigest(plugin)}!`)
await clearError(server, pluginConfig)
return true
} catch (error) {
await processError(server, pluginConfig, error)
}
} else {
await processError(server, pluginConfig, `Could not load index.js for plugin "${plugin.name}"!`)
await processError(server, pluginConfig, `Could not load index.js for ${pluginDigest(plugin)}!`)
}
} else if (plugin.plugin_type === 'source' && plugin.source) {
try {
pluginConfig.vm = await createPluginConfigVM(server, pluginConfig, plugin.source)
status.info('🔌', `Loaded plugin "${plugin.name}"!`)
status.info('🔌', `Loaded ${pluginDigest(plugin)}!`)
await clearError(server, pluginConfig)
return true
} catch (error) {
Expand All @@ -195,7 +195,7 @@ async function loadPlugin(server: PluginsServer, pluginConfig: PluginConfig): Pr
await processError(
server,
pluginConfig,
`Un-downloaded remote plugins not supported! Plugin: "${plugin.name}"`
`Un-downloaded remote plugins not supported! Tried with ${pluginDigest(plugin)}`
)
}
} catch (error) {
Expand Down
34 changes: 17 additions & 17 deletions src/sql.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import { Plugin, PluginAttachmentDB, PluginConfig, PluginConfigId, PluginError, PluginsServer } from './types'

function pluginConfigsInForceQuery(specificField?: string): string {
return `SELECT posthog_pluginconfig.${specificField || '*'}
FROM posthog_pluginconfig
LEFT JOIN posthog_team ON posthog_team.id = posthog_pluginconfig.team_id
LEFT JOIN posthog_organization ON posthog_organization.id = posthog_team.organization_id
LEFT JOIN posthog_plugin ON posthog_plugin.id = posthog_pluginconfig.plugin_id
WHERE (
posthog_pluginconfig.enabled='t' AND posthog_organization.plugins_access_level > 0
AND (posthog_plugin.organization_id = posthog_organization.id OR posthog_plugin.is_global)
)`
}

export async function getPluginRows(server: PluginsServer): Promise<Plugin[]> {
const { rows: pluginRows }: { rows: Plugin[] } = await server.db.postgresQuery(
`SELECT posthog_plugin.* FROM posthog_plugin WHERE id in
(SELECT posthog_pluginconfig.plugin_id
FROM posthog_pluginconfig
LEFT JOIN posthog_team ON posthog_team.id = posthog_pluginconfig.team_id
WHERE posthog_pluginconfig.enabled='t'
GROUP BY posthog_pluginconfig.plugin_id)`
`SELECT posthog_plugin.* FROM posthog_plugin
WHERE id IN (${pluginConfigsInForceQuery('plugin_id')} GROUP BY posthog_pluginconfig.plugin_id)`
)
return pluginRows
}

export async function getPluginAttachmentRows(server: PluginsServer): Promise<PluginAttachmentDB[]> {
const { rows }: { rows: PluginAttachmentDB[] } = await server.db.postgresQuery(
`SELECT posthog_pluginattachment.* FROM posthog_pluginattachment WHERE plugin_config_id in
(SELECT posthog_pluginconfig.id
FROM posthog_pluginconfig
LEFT JOIN posthog_team ON posthog_team.id = posthog_pluginconfig.team_id
WHERE posthog_pluginconfig.enabled='t')`
`SELECT posthog_pluginattachment.* FROM posthog_pluginattachment
WHERE plugin_config_id IN (${pluginConfigsInForceQuery('id')})`
)
return rows
}

export async function getPluginConfigRows(server: PluginsServer): Promise<PluginConfig[]> {
const { rows }: { rows: PluginConfig[] } = await server.db.postgresQuery(
`SELECT posthog_pluginconfig.*
FROM posthog_pluginconfig
LEFT JOIN posthog_team ON posthog_team.id = posthog_pluginconfig.team_id
WHERE posthog_pluginconfig.enabled='t'`
)
const { rows }: { rows: PluginConfig[] } = await server.db.postgresQuery(pluginConfigsInForceQuery())
return rows
}

Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export interface Plugin {
name: string
plugin_type: 'local' | 'respository' | 'custom' | 'source'
description?: string
is_global: boolean
url?: string
config_schema: Record<string, PluginConfigSchema> | PluginConfigSchema[]
tag?: string
Expand Down
10 changes: 9 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as tar from 'tar-stream'
import * as zlib from 'zlib'

import { status } from './status'
import { LogLevel, PluginsServerConfig, TimestampFormat } from './types'
import { LogLevel, Plugin, PluginsServerConfig, TimestampFormat } from './types'

/** Time until autoexit (due to error) gives up on graceful exit and kills the process right away. */
const GRACEFUL_EXIT_PERIOD_SECONDS = 5
Expand Down Expand Up @@ -386,3 +386,11 @@ export async function createRedis(serverConfig: PluginsServerConfig): Promise<Re
await redis.info()
return redis
}

export function pluginDigest(plugin: Plugin): string {
const extras = [`organization ${plugin.organization_id}`]
if (plugin.is_global) {
extras.push('GLOBAL')
}
return `plugin "${plugin.name}" (${extras.join(' - ')})`
}
1 change: 1 addition & 0 deletions tests/helpers/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const plugin60: Plugin = {
error: undefined,
from_json: false,
from_web: false,
is_global: false,
}

export const pluginAttachment1: PluginAttachmentDB = {
Expand Down

0 comments on commit 01537a4

Please sign in to comment.