Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cli] fix domains access permission issues #11446

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions internals/types/index.d.ts
Expand Up @@ -90,6 +90,7 @@ export interface Team {
state: string;
};
};
createdDirectToHobby?: boolean;
}

export type Domain = {
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/src/util/certs/issue-cert.ts
Expand Up @@ -13,6 +13,9 @@ export default async function issueCert(client: Client, cns: string[]) {
return await client.fetch<Cert>('/v3/now/certs', {
method: 'POST',
body: { domains: cns },
useCurrentTeam: client.authContext.enableFallbackDomainsAccess
? false
: true,
});
} catch (err: unknown) {
if (isAPIError(err) && err.code === 'configuration_error') {
Expand Down
6 changes: 6 additions & 0 deletions packages/cli/src/util/client.ts
Expand Up @@ -54,6 +54,11 @@ export interface ClientOptions extends Stdio {
agent?: Agent;
}

export interface AuthContext {
isCanonicalHobbyTeam?: boolean;
enableFallbackDomainsAccess?: boolean;
}

export const isJSONObject = (v: any): v is JSONObject => {
return v && typeof v == 'object' && v.constructor === Object;
};
Expand All @@ -72,6 +77,7 @@ export default class Client extends EventEmitter implements Stdio {
localConfigPath?: string;
requestIdCounter: number;
input;
authContext: AuthContext = {};

constructor(opts: ClientOptions) {
super();
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/src/util/deploy/generate-cert-for-deploy.ts
Expand Up @@ -4,13 +4,16 @@ import Client from '../client';
import createCertForCns from '../certs/create-cert-for-cns';
import setupDomain from '../domains/setup-domain';
import { InvalidDomain } from '../errors-ts';
import getScope from '../../util/get-scope';

export default async function generateCertForDeploy(
client: Client,
contextName: string,
deployURL: string
) {
const { output } = client;
await getScope(client);

const parsedDomain = psl.parse(deployURL);
if (parsedDomain.error) {
return new InvalidDomain(deployURL, parsedDomain.error.message);
Expand Down
31 changes: 28 additions & 3 deletions packages/cli/src/util/domains/get-domain-by-name.ts
Expand Up @@ -25,9 +25,34 @@ export default async function getDomainByName(
);
}
try {
const { domain } = await client.fetch<Response>(
`/v4/domains/${encodeURIComponent(domainName)}`
);
const { domain } = await client
.fetch<Response>(`/v4/domains/${encodeURIComponent(domainName)}`)
.catch(async err => {
// NOTE: to maintain backwards compatibility after northstar migration
// we fallback to personal account if the team is a canonical hobby team
if (isAPIError(err)) {
if (
client.authContext.isCanonicalHobbyTeam === true &&
err.status === 403
) {
return await client
.fetch<Response>(
`/v4/domains/${encodeURIComponent(domainName)}`,
{
useCurrentTeam: false,
}
)
.then(domain => {
// setting the flag so subsuquent requests to related resources (e.g., issue cert)
// are also made with the personal account auth context to avoid similar auth errors
client.authContext.enableFallbackDomainsAccess = true;
return domain;
});
}
}

throw err;
});
return domain;
} catch (err: unknown) {
if (isAPIError(err)) {
Expand Down
14 changes: 14 additions & 0 deletions packages/cli/src/util/get-scope.ts
Expand Up @@ -29,5 +29,19 @@ export default async function getScope(
contextName = team.slug;
}

/**
* isCanonicalHobbyTeam is true, if the Hobby team is the canonical team of the user account.
* Canonical Hoby team is the team that was created "automatically" upon new signups or by Northstar migration.
* A user may have multiple Hobby teams (e.g., Pro Trial downgrade), but can have only one canonical Hobby team.
*/
const isCanonicalHobbyTeam =
(team?.billing?.plan === 'hobby' &&
team.createdDirectToHobby &&
team.creatorId === user.id) ??
false;
if (isCanonicalHobbyTeam) {
client.authContext.isCanonicalHobbyTeam = true;
}

return { contextName, team, user };
}