mirror of
https://github.com/coder/coder.git
synced 2025-07-13 21:36:50 +00:00
chore: move app proxying code to workspaceapps pkg (#6998)
* chore: move app proxying code to workspaceapps pkg Moves path-app, subdomain-app and reconnecting PTY proxying to the new workspaceapps.WorkspaceAppServer struct. This is in preparation for external workspace proxies. Updates app logout flow to avoid redirecting to coder-logout.${app_host} on logout. Instead, all subdomain app tokens owned by the logging-out user will be deleted every time you logout for simplicity sake. Tests will remain in their original package, pending being moved to an apptest package (or similar). Co-authored-by: Steven Masley <stevenmasley@coder.com>
This commit is contained in:
@ -379,14 +379,14 @@ func (q *querier) GetLogoURL(ctx context.Context) (string, error) {
|
||||
return q.db.GetLogoURL(ctx)
|
||||
}
|
||||
|
||||
func (q *querier) GetAppSigningKey(ctx context.Context) (string, error) {
|
||||
func (q *querier) GetAppSecurityKey(ctx context.Context) (string, error) {
|
||||
// No authz checks
|
||||
return q.db.GetAppSigningKey(ctx)
|
||||
return q.db.GetAppSecurityKey(ctx)
|
||||
}
|
||||
|
||||
func (q *querier) InsertAppSigningKey(ctx context.Context, data string) error {
|
||||
func (q *querier) UpsertAppSecurityKey(ctx context.Context, data string) error {
|
||||
// No authz checks as this is done during startup
|
||||
return q.db.InsertAppSigningKey(ctx, data)
|
||||
return q.db.UpsertAppSecurityKey(ctx, data)
|
||||
}
|
||||
|
||||
func (q *querier) GetServiceBanner(ctx context.Context) (string, error) {
|
||||
@ -994,6 +994,16 @@ func (q *querier) GetTemplateUserRoles(ctx context.Context, id uuid.UUID) ([]dat
|
||||
return q.db.GetTemplateUserRoles(ctx, id)
|
||||
}
|
||||
|
||||
func (q *querier) DeleteApplicationConnectAPIKeysByUserID(ctx context.Context, userID uuid.UUID) error {
|
||||
// TODO: This is not 100% correct because it omits apikey IDs.
|
||||
err := q.authorizeContext(ctx, rbac.ActionDelete,
|
||||
rbac.ResourceAPIKey.WithOwner(userID.String()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return q.db.DeleteApplicationConnectAPIKeysByUserID(ctx, userID)
|
||||
}
|
||||
|
||||
func (q *querier) DeleteAPIKeysByUserID(ctx context.Context, userID uuid.UUID) error {
|
||||
// TODO: This is not 100% correct because it omits apikey IDs.
|
||||
err := q.authorizeContext(ctx, rbac.ActionDelete,
|
||||
|
@ -143,7 +143,7 @@ type data struct {
|
||||
lastUpdateCheck []byte
|
||||
serviceBanner []byte
|
||||
logoURL string
|
||||
appSigningKey string
|
||||
appSecurityKey string
|
||||
lastLicenseID int32
|
||||
}
|
||||
|
||||
@ -679,6 +679,19 @@ func (q *fakeQuerier) DeleteAPIKeyByID(_ context.Context, id string) error {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) DeleteApplicationConnectAPIKeysByUserID(_ context.Context, userID uuid.UUID) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
for i := len(q.apiKeys) - 1; i >= 0; i-- {
|
||||
if q.apiKeys[i].UserID == userID && q.apiKeys[i].Scope == database.APIKeyScopeApplicationConnect {
|
||||
q.apiKeys = append(q.apiKeys[:i], q.apiKeys[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) DeleteAPIKeysByUserID(_ context.Context, userID uuid.UUID) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
@ -4463,18 +4476,18 @@ func (q *fakeQuerier) GetLogoURL(_ context.Context) (string, error) {
|
||||
return q.logoURL, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) GetAppSigningKey(_ context.Context) (string, error) {
|
||||
func (q *fakeQuerier) GetAppSecurityKey(_ context.Context) (string, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
return q.appSigningKey, nil
|
||||
return q.appSecurityKey, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) InsertAppSigningKey(_ context.Context, data string) error {
|
||||
func (q *fakeQuerier) UpsertAppSecurityKey(_ context.Context, data string) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
q.appSigningKey = data
|
||||
q.appSecurityKey = data
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -77,12 +77,23 @@ func APIKey(t testing.TB, db database.Store, seed database.APIKey) (key database
|
||||
secret, _ := cryptorand.String(22)
|
||||
hashed := sha256.Sum256([]byte(secret))
|
||||
|
||||
ip := seed.IPAddress
|
||||
if !ip.Valid {
|
||||
ip = pqtype.Inet{
|
||||
IPNet: net.IPNet{
|
||||
IP: net.IPv4(127, 0, 0, 1),
|
||||
Mask: net.IPv4Mask(255, 255, 255, 255),
|
||||
},
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
key, err := db.InsertAPIKey(context.Background(), database.InsertAPIKeyParams{
|
||||
ID: takeFirst(seed.ID, id),
|
||||
// 0 defaults to 86400 at the db layer
|
||||
LifetimeSeconds: takeFirst(seed.LifetimeSeconds, 0),
|
||||
HashedSecret: takeFirstSlice(seed.HashedSecret, hashed[:]),
|
||||
IPAddress: pqtype.Inet{},
|
||||
IPAddress: ip,
|
||||
UserID: takeFirst(seed.UserID, uuid.New()),
|
||||
LastUsed: takeFirst(seed.LastUsed, database.Now()),
|
||||
ExpiresAt: takeFirst(seed.ExpiresAt, database.Now().Add(time.Hour)),
|
||||
|
@ -28,6 +28,7 @@ type sqlcQuerier interface {
|
||||
AcquireProvisionerJob(ctx context.Context, arg AcquireProvisionerJobParams) (ProvisionerJob, error)
|
||||
DeleteAPIKeyByID(ctx context.Context, id string) error
|
||||
DeleteAPIKeysByUserID(ctx context.Context, userID uuid.UUID) error
|
||||
DeleteApplicationConnectAPIKeysByUserID(ctx context.Context, userID uuid.UUID) error
|
||||
DeleteGitSSHKey(ctx context.Context, userID uuid.UUID) error
|
||||
DeleteGroupByID(ctx context.Context, id uuid.UUID) error
|
||||
DeleteGroupMemberFromGroup(ctx context.Context, arg DeleteGroupMemberFromGroupParams) error
|
||||
@ -46,7 +47,7 @@ type sqlcQuerier interface {
|
||||
GetAPIKeysByUserID(ctx context.Context, arg GetAPIKeysByUserIDParams) ([]APIKey, error)
|
||||
GetAPIKeysLastUsedAfter(ctx context.Context, lastUsed time.Time) ([]APIKey, error)
|
||||
GetActiveUserCount(ctx context.Context) (int64, error)
|
||||
GetAppSigningKey(ctx context.Context) (string, error)
|
||||
GetAppSecurityKey(ctx context.Context) (string, error)
|
||||
// GetAuditLogsBefore retrieves `row_limit` number of audit logs before the provided
|
||||
// ID.
|
||||
GetAuditLogsOffset(ctx context.Context, arg GetAuditLogsOffsetParams) ([]GetAuditLogsOffsetRow, error)
|
||||
@ -161,7 +162,6 @@ type sqlcQuerier interface {
|
||||
// for simplicity since all users is
|
||||
// every member of the org.
|
||||
InsertAllUsersGroup(ctx context.Context, organizationID uuid.UUID) (Group, error)
|
||||
InsertAppSigningKey(ctx context.Context, value string) error
|
||||
InsertAuditLog(ctx context.Context, arg InsertAuditLogParams) (AuditLog, error)
|
||||
InsertDERPMeshKey(ctx context.Context, value string) error
|
||||
InsertDeploymentID(ctx context.Context, value string) error
|
||||
@ -248,6 +248,7 @@ type sqlcQuerier interface {
|
||||
UpdateWorkspaceProxyDeleted(ctx context.Context, arg UpdateWorkspaceProxyDeletedParams) error
|
||||
UpdateWorkspaceTTL(ctx context.Context, arg UpdateWorkspaceTTLParams) error
|
||||
UpdateWorkspaceTTLToBeWithinTemplateMax(ctx context.Context, arg UpdateWorkspaceTTLToBeWithinTemplateMaxParams) error
|
||||
UpsertAppSecurityKey(ctx context.Context, value string) error
|
||||
UpsertLastUpdateCheck(ctx context.Context, value string) error
|
||||
UpsertLogoURL(ctx context.Context, value string) error
|
||||
UpsertServiceBanner(ctx context.Context, value string) error
|
||||
|
@ -17,8 +17,7 @@ import (
|
||||
)
|
||||
|
||||
const deleteAPIKeyByID = `-- name: DeleteAPIKeyByID :exec
|
||||
DELETE
|
||||
FROM
|
||||
DELETE FROM
|
||||
api_keys
|
||||
WHERE
|
||||
id = $1
|
||||
@ -41,6 +40,19 @@ func (q *sqlQuerier) DeleteAPIKeysByUserID(ctx context.Context, userID uuid.UUID
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteApplicationConnectAPIKeysByUserID = `-- name: DeleteApplicationConnectAPIKeysByUserID :exec
|
||||
DELETE FROM
|
||||
api_keys
|
||||
WHERE
|
||||
user_id = $1 AND
|
||||
scope = 'application_connect'::api_key_scope
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) DeleteApplicationConnectAPIKeysByUserID(ctx context.Context, userID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteApplicationConnectAPIKeysByUserID, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
const getAPIKeyByID = `-- name: GetAPIKeyByID :one
|
||||
SELECT
|
||||
id, hashed_secret, user_id, last_used, expires_at, created_at, updated_at, login_type, lifetime_seconds, ip_address, scope, token_name
|
||||
@ -3202,12 +3214,12 @@ func (q *sqlQuerier) UpdateReplica(ctx context.Context, arg UpdateReplicaParams)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getAppSigningKey = `-- name: GetAppSigningKey :one
|
||||
const getAppSecurityKey = `-- name: GetAppSecurityKey :one
|
||||
SELECT value FROM site_configs WHERE key = 'app_signing_key'
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetAppSigningKey(ctx context.Context) (string, error) {
|
||||
row := q.db.QueryRowContext(ctx, getAppSigningKey)
|
||||
func (q *sqlQuerier) GetAppSecurityKey(ctx context.Context) (string, error) {
|
||||
row := q.db.QueryRowContext(ctx, getAppSecurityKey)
|
||||
var value string
|
||||
err := row.Scan(&value)
|
||||
return value, err
|
||||
@ -3268,15 +3280,6 @@ func (q *sqlQuerier) GetServiceBanner(ctx context.Context) (string, error) {
|
||||
return value, err
|
||||
}
|
||||
|
||||
const insertAppSigningKey = `-- name: InsertAppSigningKey :exec
|
||||
INSERT INTO site_configs (key, value) VALUES ('app_signing_key', $1)
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) InsertAppSigningKey(ctx context.Context, value string) error {
|
||||
_, err := q.db.ExecContext(ctx, insertAppSigningKey, value)
|
||||
return err
|
||||
}
|
||||
|
||||
const insertDERPMeshKey = `-- name: InsertDERPMeshKey :exec
|
||||
INSERT INTO site_configs (key, value) VALUES ('derp_mesh_key', $1)
|
||||
`
|
||||
@ -3295,6 +3298,16 @@ func (q *sqlQuerier) InsertDeploymentID(ctx context.Context, value string) error
|
||||
return err
|
||||
}
|
||||
|
||||
const upsertAppSecurityKey = `-- name: UpsertAppSecurityKey :exec
|
||||
INSERT INTO site_configs (key, value) VALUES ('app_signing_key', $1)
|
||||
ON CONFLICT (key) DO UPDATE set value = $1 WHERE site_configs.key = 'app_signing_key'
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) UpsertAppSecurityKey(ctx context.Context, value string) error {
|
||||
_, err := q.db.ExecContext(ctx, upsertAppSecurityKey, value)
|
||||
return err
|
||||
}
|
||||
|
||||
const upsertLastUpdateCheck = `-- name: UpsertLastUpdateCheck :exec
|
||||
INSERT INTO site_configs (key, value) VALUES ('last_update_check', $1)
|
||||
ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'last_update_check'
|
||||
|
@ -66,12 +66,18 @@ WHERE
|
||||
id = $1;
|
||||
|
||||
-- name: DeleteAPIKeyByID :exec
|
||||
DELETE
|
||||
FROM
|
||||
DELETE FROM
|
||||
api_keys
|
||||
WHERE
|
||||
id = $1;
|
||||
|
||||
-- name: DeleteApplicationConnectAPIKeysByUserID :exec
|
||||
DELETE FROM
|
||||
api_keys
|
||||
WHERE
|
||||
user_id = $1 AND
|
||||
scope = 'application_connect'::api_key_scope;
|
||||
|
||||
-- name: DeleteAPIKeysByUserID :exec
|
||||
DELETE FROM
|
||||
api_keys
|
||||
|
@ -31,8 +31,9 @@ ON CONFLICT (key) DO UPDATE SET value = $1 WHERE site_configs.key = 'logo_url';
|
||||
-- name: GetLogoURL :one
|
||||
SELECT value FROM site_configs WHERE key = 'logo_url';
|
||||
|
||||
-- name: GetAppSigningKey :one
|
||||
-- name: GetAppSecurityKey :one
|
||||
SELECT value FROM site_configs WHERE key = 'app_signing_key';
|
||||
|
||||
-- name: InsertAppSigningKey :exec
|
||||
INSERT INTO site_configs (key, value) VALUES ('app_signing_key', $1);
|
||||
-- name: UpsertAppSecurityKey :exec
|
||||
INSERT INTO site_configs (key, value) VALUES ('app_signing_key', $1)
|
||||
ON CONFLICT (key) DO UPDATE set value = $1 WHERE site_configs.key = 'app_signing_key';
|
||||
|
Reference in New Issue
Block a user