@capgo/cli 4.0.11 → 4.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ const antfu = require('@antfu/eslint-config').default
2
+
3
+ module.exports = antfu()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/cli",
3
- "version": "4.0.11",
3
+ "version": "4.0.13",
4
4
  "description": "A CLI to upload to capgo servers",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -38,7 +38,7 @@
38
38
  "pack": "pkg",
39
39
  "types": "npx --yes supabase gen types typescript --project-id=xvwzpoazmxkqosrdewyv > src/types/supabase.types.ts",
40
40
  "test_rls": "ts-node ./test/test_headers_rls.ts",
41
- "lint": "eslint . --ext .ts --fix"
41
+ "lint": "eslint \"src/**/*.ts\" --fix"
42
42
  },
43
43
  "author": "github.com/riderx",
44
44
  "license": "Apache 2.0",
@@ -65,6 +65,7 @@
65
65
  "semver": "^7.6.0"
66
66
  },
67
67
  "devDependencies": {
68
+ "@antfu/eslint-config": "^2.6.4",
68
69
  "@types/adm-zip": "0.5.5",
69
70
  "@types/mime": "^3.0.4",
70
71
  "@types/node": "^20.11.17",
package/src/api/app.ts CHANGED
@@ -1,56 +1,50 @@
1
- import { SupabaseClient } from '@supabase/supabase-js';
2
- import * as p from '@clack/prompts';
3
- import { program } from 'commander';
4
- import { Database } from '../types/supabase.types';
5
- import { isAllowedApp, isAllowedAppOrg, OptionsBase, OrganizationPerm } from '../utils';
1
+ import type { SupabaseClient } from '@supabase/supabase-js'
2
+ import * as p from '@clack/prompts'
3
+ import { program } from 'commander'
4
+ import type { Database } from '../types/supabase.types'
5
+ import type { OptionsBase } from '../utils'
6
+ import { OrganizationPerm, isAllowedApp, isAllowedAppOrg } from '../utils'
6
7
 
7
- export const checkAppExists = async (supabase: SupabaseClient<Database>, appid: string) => {
8
+ export async function checkAppExists(supabase: SupabaseClient<Database>, appid: string) {
8
9
  const { data: app } = await supabase
9
10
  .rpc('exist_app_v2', { appid })
10
- .single();
11
- return !!app;
11
+ .single()
12
+ return !!app
12
13
  }
13
14
 
14
- export const checkAppExistsAndHasPermissionErr = async (supabase: SupabaseClient<Database>, apikey: string, appid: string,
15
- shouldExist = true) => {
16
- const res = await checkAppExists(supabase, appid);
17
- const perm = await isAllowedApp(supabase, apikey, appid);
15
+ export async function checkAppExistsAndHasPermissionErr(supabase: SupabaseClient<Database>, apikey: string, appid: string, shouldExist = true) {
16
+ const res = await checkAppExists(supabase, appid)
17
+ const perm = await isAllowedApp(supabase, apikey, appid)
18
18
 
19
19
  if (res && !shouldExist) {
20
- p.log.error(`App ${appid} already exist`);
21
- program.error('');
20
+ p.log.error(`App ${appid} already exist`)
21
+ program.error('')
22
22
  }
23
23
  if (!res && shouldExist) {
24
- p.log.error(`App ${appid} does not exist`);
25
- program.error('');
24
+ p.log.error(`App ${appid} does not exist`)
25
+ program.error('')
26
26
  }
27
27
  if (res && !perm) {
28
- p.log.error(`App ${appid} exist and you don't have permission to access it`);
29
- if (appid === 'io.ionic.starter') {
30
- p.log.info('Modify your appid in your capacitor.config.json file to something unique, this is a default appid for ionic starter app');
31
- }
32
- program.error('');
28
+ p.log.error(`App ${appid} exist and you don't have permission to access it`)
29
+ if (appid === 'io.ionic.starter')
30
+ p.log.info('Modify your appid in your capacitor.config.json file to something unique, this is a default appid for ionic starter app')
31
+
32
+ program.error('')
33
33
  }
34
34
  }
35
35
 
36
- export const checkAppExistsAndHasPermissionOrgErr = async (
37
- supabase: SupabaseClient<Database>,
38
- apikey: string,
39
- appid: string,
40
- requiredPermission: OrganizationPerm
41
- ) => {
36
+ export async function checkAppExistsAndHasPermissionOrgErr(supabase: SupabaseClient<Database>, apikey: string, appid: string, requiredPermission: OrganizationPerm) {
42
37
  const permissions = await isAllowedAppOrg(supabase, apikey, appid)
43
38
  if (!permissions.okay) {
44
- // eslint-disable-next-line default-case
45
39
  switch (permissions.error) {
46
40
  case 'INVALID_APIKEY': {
47
41
  p.log.error('Invalid apikey, such apikey does not exists!')
48
- program.error('');
42
+ program.error('')
49
43
  break
50
44
  }
51
45
  case 'NO_APP': {
52
- p.log.error(`App ${appid} does not exist`);
53
- program.error('');
46
+ p.log.error(`App ${appid} does not exist`)
47
+ program.error('')
54
48
  break
55
49
  }
56
50
  case 'NO_ORG': {
@@ -65,7 +59,6 @@ export const checkAppExistsAndHasPermissionOrgErr = async (
65
59
  const requiredPermNumber = requiredPermission as number
66
60
 
67
61
  if (requiredPermNumber > remotePermNumber) {
68
- // eslint-disable-next-line max-len
69
62
  p.log.error(`Insuficcent permissions for app ${appid}. Current permission: ${OrganizationPerm[permissions.data]}, required for this action: ${OrganizationPerm[requiredPermission]}.`)
70
63
  program.error('')
71
64
  }
@@ -74,9 +67,9 @@ export const checkAppExistsAndHasPermissionOrgErr = async (
74
67
  }
75
68
 
76
69
  export interface Options extends OptionsBase {
77
- name?: string;
78
- icon?: string;
79
- retention?: number;
70
+ name?: string
71
+ icon?: string
72
+ retention?: number
80
73
  }
81
74
 
82
- export const newIconPath = "assets/icon.png"
75
+ export const newIconPath = 'assets/icon.png'
@@ -1,12 +1,12 @@
1
- import { SupabaseClient } from '@supabase/supabase-js';
2
- import { program } from 'commander';
3
- import { Table } from 'console-table-printer';
4
- import * as p from '@clack/prompts';
5
- import { Database } from '../types/supabase.types';
6
- import { formatError, getHumanDate } from '../utils';
1
+ import process from 'node:process'
2
+ import type { SupabaseClient } from '@supabase/supabase-js'
3
+ import { program } from 'commander'
4
+ import { Table } from 'console-table-printer'
5
+ import * as p from '@clack/prompts'
6
+ import type { Database } from '../types/supabase.types'
7
+ import { formatError, getHumanDate } from '../utils'
7
8
 
8
- export const checkVersionNotUsedInChannel = async (supabase: SupabaseClient<Database>,
9
- appid: string, userId: string, versionData: Database['public']['Tables']['app_versions']['Row']) => {
9
+ export async function checkVersionNotUsedInChannel(supabase: SupabaseClient<Database>, appid: string, userId: string, versionData: Database['public']['Tables']['app_versions']['Row']) {
10
10
  const { data: channelFound, error: errorChannel } = await supabase
11
11
  .from('channels')
12
12
  .select()
@@ -14,20 +14,20 @@ export const checkVersionNotUsedInChannel = async (supabase: SupabaseClient<Data
14
14
  .eq('created_by', userId)
15
15
  .eq('version', versionData.id)
16
16
  if (errorChannel) {
17
- p.log.error(`Cannot check Version ${appid}@${versionData.name}`);
18
- program.error('');
17
+ p.log.error(`Cannot check Version ${appid}@${versionData.name}`)
18
+ program.error('')
19
19
  }
20
20
  if (channelFound && channelFound.length > 0) {
21
21
  p.intro(`❌ Version ${appid}@${versionData.name} is used in ${channelFound.length} channel`)
22
22
  if (await p.confirm({ message: 'unlink it?' })) {
23
23
  // loop on all channels and set version to unknown
24
24
  for (const channel of channelFound) {
25
- const s = p.spinner();
25
+ const s = p.spinner()
26
26
  s.start(`Unlinking channel ${channel.name}`)
27
27
  const { error: errorChannelUpdate } = await supabase
28
28
  .from('channels')
29
29
  .update({
30
- version: (await findUnknownVersion(supabase, appid))?.id
30
+ version: (await findUnknownVersion(supabase, appid))?.id,
31
31
  })
32
32
  .eq('id', channel.id)
33
33
  if (errorChannelUpdate) {
@@ -38,66 +38,70 @@ export const checkVersionNotUsedInChannel = async (supabase: SupabaseClient<Data
38
38
  }
39
39
  }
40
40
  else {
41
- p.log.error(`Unlink it first`);
42
- program.error('');
41
+ p.log.error(`Unlink it first`)
42
+ program.error('')
43
43
  }
44
44
  p.outro(`Version unlinked from ${channelFound.length} channel`)
45
45
  }
46
46
  }
47
47
 
48
- export const findUnknownVersion = (supabase: SupabaseClient<Database>, appId: string) => supabase
49
- .from('app_versions')
50
- .select('id')
51
- .eq('app_id', appId)
52
- .eq('name', 'unknown')
53
- .throwOnError()
54
- .single().then(({ data }) => data)
55
-
56
-
57
- export const createChannel = (supabase: SupabaseClient<Database>, update: Database['public']['Tables']['channels']['Insert']) => supabase
58
- .from('channels')
59
- .insert(update)
60
- .select()
61
- .single()
48
+ export function findUnknownVersion(supabase: SupabaseClient<Database>, appId: string) {
49
+ return supabase
50
+ .from('app_versions')
51
+ .select('id')
52
+ .eq('app_id', appId)
53
+ .eq('name', 'unknown')
54
+ .throwOnError()
55
+ .single().then(({ data }) => data)
56
+ }
62
57
 
63
- export const delChannel = (supabase: SupabaseClient<Database>, name: string, appId: string, userId: string) => supabase
64
- .from('channels')
65
- .delete()
66
- .eq('name', name)
67
- .eq('app_id', appId)
68
- .eq('created_by', userId)
69
- .single()
58
+ export function createChannel(supabase: SupabaseClient<Database>, update: Database['public']['Tables']['channels']['Insert']) {
59
+ return supabase
60
+ .from('channels')
61
+ .insert(update)
62
+ .select()
63
+ .single()
64
+ }
70
65
 
66
+ export function delChannel(supabase: SupabaseClient<Database>, name: string, appId: string, userId: string) {
67
+ return supabase
68
+ .from('channels')
69
+ .delete()
70
+ .eq('name', name)
71
+ .eq('app_id', appId)
72
+ .eq('created_by', userId)
73
+ .single()
74
+ }
71
75
 
72
- export const displayChannels = (data: (Database['public']['Tables']['channels']['Row'] & { keep?: string })[]) => {
76
+ export function displayChannels(data: (Database['public']['Tables']['channels']['Row'] & { keep?: string })[]) {
73
77
  const t = new Table({
74
- title: "Channels",
75
- charLength: { "": 2, "": 2 },
76
- });
78
+ title: 'Channels',
79
+ charLength: { '': 2, '': 2 },
80
+ })
77
81
 
78
82
  // add rows with color
79
- data.reverse().forEach(row => {
83
+ data.reverse().forEach((row) => {
80
84
  t.addRow({
81
85
  Name: row.name,
82
86
  Created: getHumanDate(row.created_at),
83
- Public: row.public ? '✅' : '❌'
84
- });
85
- });
87
+ Public: row.public ? '✅' : '❌',
88
+ })
89
+ })
86
90
 
87
- p.log.success(t.render());
91
+ p.log.success(t.render())
88
92
  }
89
93
 
90
- export const getActiveChannels = async (supabase: SupabaseClient<Database>, appid: string) => {
94
+ export async function getActiveChannels(supabase: SupabaseClient<Database>, appid: string) {
91
95
  const { data, error: vError } = await supabase
92
96
  .from('channels')
93
97
  .select()
94
98
  .eq('app_id', appid)
95
99
  // .eq('created_by', userId)
96
- .order('created_at', { ascending: false });
100
+ .order('created_at', { ascending: false })
97
101
 
98
102
  if (vError) {
99
- p.log.error(`App ${appid} not found in database`);
100
- program.error('');
103
+ p.log.error(`App ${appid} not found in database`)
104
+ program.error('')
101
105
  }
102
- return data;
106
+ return data
103
107
  }
package/src/api/crypto.ts CHANGED
@@ -1,97 +1,100 @@
1
-
2
1
  import {
3
- generateKeyPairSync,
4
- constants,
5
- publicEncrypt, privateDecrypt,
6
- randomBytes, createCipheriv, createDecipheriv
7
- } from 'node:crypto';
2
+ constants,
3
+ createCipheriv,
4
+ createDecipheriv,
5
+ generateKeyPairSync,
6
+ privateDecrypt,
7
+ publicEncrypt,
8
+ randomBytes,
9
+ } from 'node:crypto'
10
+ import { Buffer } from 'node:buffer'
8
11
 
9
- const algorithm = "aes-128-cbc";
10
- const oaepHash = 'sha256';
11
- const formatB64 = 'base64';
12
- const padding = constants.RSA_PKCS1_OAEP_PADDING;
12
+ const algorithm = 'aes-128-cbc'
13
+ const oaepHash = 'sha256'
14
+ const formatB64 = 'base64'
15
+ const padding = constants.RSA_PKCS1_OAEP_PADDING
13
16
 
14
- export const decryptSource = (source: Buffer, ivSessionKey: string, privateKey: string): Buffer => {
15
- // console.log('\nivSessionKey', ivSessionKey)
16
- const [ivB64, sessionb64Encrypted] = ivSessionKey.split(':');
17
- // console.log('\nsessionb64Encrypted', sessionb64Encrypted)
18
- // console.log('\nivB64', ivB64)
19
- const sessionKey = privateDecrypt(
20
- {
21
- key: privateKey,
22
- padding,
23
- oaepHash,
24
- },
25
- Buffer.from(sessionb64Encrypted, formatB64)
26
- )
27
- // ivB64 to uft-8
28
- const initVector = Buffer.from(ivB64, formatB64);
29
- // console.log('\nSessionB64', sessionB64)
17
+ export function decryptSource(source: Buffer, ivSessionKey: string, privateKey: string): Buffer {
18
+ // console.log('\nivSessionKey', ivSessionKey)
19
+ const [ivB64, sessionb64Encrypted] = ivSessionKey.split(':')
20
+ // console.log('\nsessionb64Encrypted', sessionb64Encrypted)
21
+ // console.log('\nivB64', ivB64)
22
+ const sessionKey = privateDecrypt(
23
+ {
24
+ key: privateKey,
25
+ padding,
26
+ oaepHash,
27
+ },
28
+ Buffer.from(sessionb64Encrypted, formatB64),
29
+ )
30
+ // ivB64 to uft-8
31
+ const initVector = Buffer.from(ivB64, formatB64)
32
+ // console.log('\nSessionB64', sessionB64)
30
33
 
31
- const decipher = createDecipheriv(algorithm, sessionKey, initVector);
32
- decipher.setAutoPadding(true);
33
- const decryptedData = Buffer.concat([decipher.update(source), decipher.final()]);
34
+ const decipher = createDecipheriv(algorithm, sessionKey, initVector)
35
+ decipher.setAutoPadding(true)
36
+ const decryptedData = Buffer.concat([decipher.update(source), decipher.final()])
34
37
 
35
- return decryptedData
38
+ return decryptedData
36
39
  }
37
40
  export interface Encoded {
38
- ivSessionKey: string,
39
- encryptedData: Buffer
41
+ ivSessionKey: string
42
+ encryptedData: Buffer
40
43
  }
41
- export const encryptSource = (source: Buffer, publicKey: string): Encoded => {
42
- // encrypt zip with key
43
- const initVector = randomBytes(16);
44
- const sessionKey = randomBytes(16);
45
- // encrypt session key with public key
46
- // console.log('\nencrypted.key', encrypted.key.toString(CryptoJS.enc.Base64))
47
- const cipher = createCipheriv(algorithm, sessionKey, initVector);
48
- cipher.setAutoPadding(true);
49
- // console.log('\nsessionKey', sessionKey.toString())
50
- // const sessionB64 = sessionKey.toString(formatB64)
51
- // console.log('\nsessionB64', sessionB64)
52
- const ivB64 = initVector.toString(formatB64);
53
- // console.log('\nivB64', ivB64)
54
- const sessionb64Encrypted = publicEncrypt(
55
- {
56
- key: publicKey,
57
- padding,
58
- oaepHash,
59
- },
60
- sessionKey
61
- ).toString(formatB64)
62
- // console.log('\nsessionb64Encrypted', sessionb64Encrypted)
63
- const ivSessionKey = `${ivB64}:${sessionb64Encrypted}`
64
- // console.log('\nivSessionKey', sessionKey)
65
- // encrypted to buffer
44
+ export function encryptSource(source: Buffer, publicKey: string): Encoded {
45
+ // encrypt zip with key
46
+ const initVector = randomBytes(16)
47
+ const sessionKey = randomBytes(16)
48
+ // encrypt session key with public key
49
+ // console.log('\nencrypted.key', encrypted.key.toString(CryptoJS.enc.Base64))
50
+ const cipher = createCipheriv(algorithm, sessionKey, initVector)
51
+ cipher.setAutoPadding(true)
52
+ // console.log('\nsessionKey', sessionKey.toString())
53
+ // const sessionB64 = sessionKey.toString(formatB64)
54
+ // console.log('\nsessionB64', sessionB64)
55
+ const ivB64 = initVector.toString(formatB64)
56
+ // console.log('\nivB64', ivB64)
57
+ const sessionb64Encrypted = publicEncrypt(
58
+ {
59
+ key: publicKey,
60
+ padding,
61
+ oaepHash,
62
+ },
63
+ sessionKey,
64
+ ).toString(formatB64)
65
+ // console.log('\nsessionb64Encrypted', sessionb64Encrypted)
66
+ const ivSessionKey = `${ivB64}:${sessionb64Encrypted}`
67
+ // console.log('\nivSessionKey', sessionKey)
68
+ // encrypted to buffer
66
69
 
67
- const encryptedData = Buffer.concat([cipher.update(source), cipher.final()]);
70
+ const encryptedData = Buffer.concat([cipher.update(source), cipher.final()])
68
71
 
69
- return {
70
- encryptedData,
71
- ivSessionKey
72
- }
72
+ return {
73
+ encryptedData,
74
+ ivSessionKey,
75
+ }
73
76
  }
74
77
  export interface RSAKeys {
75
- publicKey: string,
76
- privateKey: string
78
+ publicKey: string
79
+ privateKey: string
77
80
  }
78
- export const createRSA = (): RSAKeys => {
79
- const { publicKey, privateKey } = generateKeyPairSync("rsa", {
80
- // The standard secure default length for RSA keys is 2048 bits
81
- modulusLength: 2048,
82
- })
81
+ export function createRSA(): RSAKeys {
82
+ const { publicKey, privateKey } = generateKeyPairSync('rsa', {
83
+ // The standard secure default length for RSA keys is 2048 bits
84
+ modulusLength: 2048,
85
+ })
83
86
 
84
- // Generate RSA key pair
85
- return {
86
- publicKey: publicKey.export({
87
- type: "pkcs1",
88
- format: "pem",
89
- }) as string,
90
- privateKey: privateKey.export({
91
- type: "pkcs1",
92
- format: "pem",
93
- }) as string,
94
- }
87
+ // Generate RSA key pair
88
+ return {
89
+ publicKey: publicKey.export({
90
+ type: 'pkcs1',
91
+ format: 'pem',
92
+ }) as string,
93
+ privateKey: privateKey.export({
94
+ type: 'pkcs1',
95
+ format: 'pem',
96
+ }) as string,
97
+ }
95
98
  }
96
99
  // test AES
97
100
 
@@ -1,27 +1,26 @@
1
- import { SupabaseClient } from '@supabase/supabase-js';
2
- import { program } from 'commander';
3
- import * as p from '@clack/prompts';
4
- import { Database } from '../types/supabase.types';
5
- import { formatError } from '../utils';
6
-
7
- export const checkVersionNotUsedInDeviceOverride = async (supabase: SupabaseClient<Database>,
8
- appid: string, versionData: Database['public']['Tables']['app_versions']['Row']) => {
1
+ import process from 'node:process'
2
+ import type { SupabaseClient } from '@supabase/supabase-js'
3
+ import { program } from 'commander'
4
+ import * as p from '@clack/prompts'
5
+ import type { Database } from '../types/supabase.types'
6
+ import { formatError } from '../utils'
9
7
 
8
+ export async function checkVersionNotUsedInDeviceOverride(supabase: SupabaseClient<Database>, appid: string, versionData: Database['public']['Tables']['app_versions']['Row']) {
10
9
  const { data: deviceFound, error: errorDevice } = await supabase
11
10
  .from('devices_override')
12
11
  .select()
13
12
  .eq('app_id', appid)
14
13
  .eq('version', versionData.id)
15
14
  if (errorDevice) {
16
- p.log.error(`Cannot check Device override ${appid}@${versionData.name}`);
17
- program.error('');
15
+ p.log.error(`Cannot check Device override ${appid}@${versionData.name}`)
16
+ program.error('')
18
17
  }
19
18
  if (deviceFound && deviceFound.length > 0) {
20
19
  p.intro(`❌ Version ${appid}@${versionData.name} is used in ${deviceFound.length} device override`)
21
20
  if (await p.confirm({ message: 'unlink it?' })) {
22
21
  // loop on all devices and set version to unknown
23
22
  for (const device of deviceFound) {
24
- const s = p.spinner();
23
+ const s = p.spinner()
25
24
  s.start(`Unlinking device ${device.device_id}`)
26
25
  const { error: errorDeviceDel } = await supabase
27
26
  .from('devices_override')
@@ -35,8 +34,8 @@ export const checkVersionNotUsedInDeviceOverride = async (supabase: SupabaseClie
35
34
  }
36
35
  }
37
36
  else {
38
- p.log.error(`Unlink it first`);
39
- program.error('');
37
+ p.log.error(`Unlink it first`)
38
+ program.error('')
40
39
  }
41
40
  }
42
41
  }
package/src/api/update.ts CHANGED
@@ -1,12 +1,12 @@
1
- import getLatest from "get-latest-version"
2
- import * as p from '@clack/prompts';
1
+ import getLatest from 'get-latest-version'
2
+ import * as p from '@clack/prompts'
3
3
  import pack from '../../package.json'
4
4
 
5
- export const checkLatest = async () => {
6
- const latest = await getLatest('@capgo/cli')
7
- if (latest !== pack.version) {
8
- p.log.warning(`🚨 You are using @capgo/cli@${pack.version} it's not the latest version.
9
- Please use @capgo/cli@${latest}" or @capgo/cli@latest to keep up to date with the latest features and bug fixes.`
10
- )
11
- }
12
- }
5
+ export async function checkLatest() {
6
+ const latest = await getLatest('@capgo/cli')
7
+ if (latest !== pack.version) {
8
+ p.log.warning(`🚨 You are using @capgo/cli@${pack.version} it's not the latest version.
9
+ Please use @capgo/cli@${latest}" or @capgo/cli@latest to keep up to date with the latest features and bug fixes.`,
10
+ )
11
+ }
12
+ }