update ESLint (#636)
* update ESLint * f * f * f * c * f * f * f * f * r * u * f * f * u
This commit is contained in:
parent
27ba1bd931
commit
3c71b8c8f8
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
'@status-im/eslint-config': patch
|
||||
'@status-im/components': patch
|
||||
'@status-im/js': patch
|
||||
'@status-im/colors': patch
|
||||
'connector': patch
|
||||
'@status-im/icons': patch
|
||||
---
|
||||
|
||||
update ESLint
|
|
@ -1,6 +0,0 @@
|
|||
**/dist
|
||||
**/node_modules
|
||||
**/protos
|
||||
**/proto
|
||||
**/coverage
|
||||
**/storybook-static
|
|
@ -1,7 +1,13 @@
|
|||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"npm.packageManager": "pnpm",
|
||||
"eslint.useESLintClass": true,
|
||||
"eslint.workingDirectories": [
|
||||
"./packages/colors",
|
||||
"./packages/icons",
|
||||
"./packages/components",
|
||||
"./packages/status-js",
|
||||
"./apps/connector",
|
||||
{
|
||||
"mode": "auto",
|
||||
"#comment": "See https://github.com/microsoft/vscode-eslint/issues/1161 for reason (i.e. multiple .eslintrc config files)"
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
extends: ['@status-im/eslint-config', 'plugin:tailwindcss/recommended'],
|
||||
|
||||
rules: {
|
||||
'no-constant-binary-expression': 'error',
|
||||
'no-restricted-globals': ['error', 'process'],
|
||||
'jsx-a11y/alt-text': [
|
||||
1,
|
||||
{
|
||||
img: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
// parser: 'esprima',
|
||||
files: ['*.mjs'],
|
||||
// env: {
|
||||
// browser: true,
|
||||
// es2021: true,
|
||||
// },
|
||||
// extends: ['eslint:recommended', 'plugin:import/recommended'],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.js'],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
|
@ -62,10 +62,10 @@ pipeline {
|
|||
expression { changesDetected }
|
||||
}
|
||||
steps {
|
||||
dir("${env.WORKSPACE}/apps/connector") {
|
||||
dir("${env.WORKSPACE}") {
|
||||
script {
|
||||
nix.shell(
|
||||
'pnpm build:chrome',
|
||||
'pnpm turbo run build --filter=connector',
|
||||
pure: false,
|
||||
entryPoint: "${env.WORKSPACE}/apps/connector/shell.nix"
|
||||
)
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import configs, { tailwindcssConfigs } from '@status-im/eslint-config'
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
...configs,
|
||||
...tailwindcssConfigs,
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
rules: {
|
||||
'no-constant-binary-expression': 'error',
|
||||
'no-restricted-globals': ['error', 'process'],
|
||||
'jsx-a11y/alt-text': [
|
||||
1,
|
||||
{
|
||||
img: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.mjs'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.js'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
|
@ -13,9 +13,10 @@
|
|||
"dev:chrome": "plasmo dev --target=chrome-mv3",
|
||||
"dev:safari": "plasmo dev --target=safari-mv3",
|
||||
"dev:firefox": "plasmo dev --target=firefox-mv3",
|
||||
"build": "pnpm build:chrome",
|
||||
"build:chrome": "plasmo build --target=chrome-mv3",
|
||||
"build:firefox": "plasmo build --target=firefox-mv3 --zip",
|
||||
"lint": "eslint ./src",
|
||||
"lint": "eslint src",
|
||||
"format": "prettier --write .",
|
||||
"package": "plasmo package",
|
||||
"clean": "rimraf apps build .plasmo node_modules"
|
||||
|
@ -25,7 +26,7 @@
|
|||
"@plasmohq/storage": "^1.11.0",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||
"@radix-ui/react-switch": "^1.1.0",
|
||||
"@status-im/colors": "^0.4.0",
|
||||
"@status-im/colors": "workspace:*",
|
||||
"cva": "^1.0.0-beta.1",
|
||||
"ethers": "^6.13.0",
|
||||
"plasmo": "0.88.0",
|
||||
|
@ -37,7 +38,7 @@
|
|||
"devDependencies": {
|
||||
"@ianvs/prettier-plugin-sort-imports": "4.1.1",
|
||||
"@parcel/bundler-experimental": "^2.7.0",
|
||||
"@status-im/eslint-config": "^0.3.0",
|
||||
"@status-im/eslint-config": "workspace:*",
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"@types/chrome": "0.0.258",
|
||||
"@types/node": "20.11.5",
|
||||
|
@ -45,7 +46,6 @@
|
|||
"@types/react-dom": "18.2.18",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^13.2.0",
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "3.2.4",
|
||||
"prettier-plugin-tailwindcss": "^0.6.1",
|
||||
|
|
|
@ -9,8 +9,8 @@ const styles = cva({
|
|||
base: 'flex h-6 items-center gap-1 rounded-[20px] border px-2 text-13',
|
||||
variants: {
|
||||
status: {
|
||||
on: 'border-success-/20 bg-success-/10 text-success-60',
|
||||
off: 'border-danger-/20 bg-danger-/10 text-danger-60',
|
||||
on: 'border-success-50/20 bg-success-50/10 text-success-60',
|
||||
off: 'border-danger-50/20 bg-danger-50/10 text-danger-60',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -127,7 +127,7 @@ export class Provider {
|
|||
return
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// we don't reject here because incoming message is not from the proxy
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
{
|
||||
ignores: [
|
||||
'**/dist',
|
||||
'**/node_modules',
|
||||
'**/protos',
|
||||
'**/proto',
|
||||
'**/coverage',
|
||||
'**/storybook-static',
|
||||
],
|
||||
},
|
||||
]
|
10
package.json
10
package.json
|
@ -7,7 +7,8 @@
|
|||
"packages/status-js",
|
||||
"packages/colors",
|
||||
"packages/icons",
|
||||
"packages/components"
|
||||
"packages/components",
|
||||
"apps/connector"
|
||||
]
|
||||
},
|
||||
"keywords": [],
|
||||
|
@ -16,8 +17,8 @@
|
|||
"prepare": "husky install",
|
||||
"test": "turbo run test --filter=@status-im/* -- --run",
|
||||
"dev": "turbo run dev --filter=@status-im/* --parallel",
|
||||
"build": "turbo run build --filter=@status-im/* && node --version",
|
||||
"lint": "turbo run lint --filter=@status-im/* --filter=web",
|
||||
"build": "turbo run build --filter=@status-im/* --filter=connector",
|
||||
"lint": "turbo run lint --filter=@status-im/* --filter=connector",
|
||||
"typecheck": "turbo run typecheck",
|
||||
"format": "prettier --write .",
|
||||
"clean": "turbo run clean && rimraf node_modules",
|
||||
|
@ -32,8 +33,9 @@
|
|||
"@status-im/eslint-config": "workspace:*",
|
||||
"@tsconfig/strictest": "^2.0.0",
|
||||
"@types/prettier": "^2.7.2",
|
||||
"eslint": "^9.14.0",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^13.2.0",
|
||||
"lint-staged": "^15.2.10",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.6",
|
||||
"@types/react": "^18.0.33",
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"extends": ["@status-im/eslint-config"]
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
import configs from '@status-im/eslint-config'
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [...configs]
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"extends": ["plugin:tailwindcss/recommended", "@status-im/eslint-config"],
|
||||
"rules": {
|
||||
"tailwindcss/classnames-order": "off"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
import configs, { tailwindcssConfigs } from '@status-im/eslint-config'
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [...configs, ...tailwindcssConfigs]
|
|
@ -31,7 +31,7 @@
|
|||
"preinstall": "npx only-allow pnpm",
|
||||
"dev": "vite build --watch --mode development",
|
||||
"build": "vite build",
|
||||
"postbuild": "pnpm build:types && node --version",
|
||||
"postbuild": "pnpm build:types",
|
||||
"build:types": "tsc --noEmit false --emitDeclarationOnly",
|
||||
"typecheck": "tsc",
|
||||
"lint": "eslint src",
|
||||
|
|
|
@ -14,6 +14,7 @@ const sizesAvatar = {
|
|||
}
|
||||
|
||||
const renderVariant = (variant: AvatarProps['type']) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const content = (props: any) => {
|
||||
const sizes = sizesAvatar[variant]
|
||||
|
||||
|
@ -47,7 +48,7 @@ const meta = {
|
|||
},
|
||||
|
||||
render: props => (
|
||||
<div className="grid gap-4 theme-yellow">
|
||||
<div className="grid gap-4">
|
||||
<h1 className="text-19">User Avatar</h1>
|
||||
{renderVariant('user')({
|
||||
...props,
|
||||
|
|
|
@ -7,7 +7,7 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||
|
||||
const sizes = ['40', '32', '24'] as const
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const renderVariant = (variant: string) => (props: any) => (
|
||||
<div className="flex items-center gap-4">
|
||||
{sizes.map(size => (
|
||||
|
|
|
@ -6,7 +6,7 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||
|
||||
const variants = ['primary', 'secondary', 'gray'] as const
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const renderVariant = (variant: (typeof variants)[number]) => (props: any) => (
|
||||
<div className="flex items-center gap-2">
|
||||
<Shortcut {...props} variant={variant} icon={<CommandIcon />} />
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { cva, cx, type VariantProps } from 'cva'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const styles = cva({
|
||||
base: 'animate-skeleton overflow-hidden',
|
||||
|
||||
|
|
|
@ -27,13 +27,7 @@ function Tag(
|
|||
props: Props & (ButtonProps | DivProps),
|
||||
ref: Ref<HTMLButtonElement | HTMLDivElement>,
|
||||
) {
|
||||
const {
|
||||
size = '32',
|
||||
icon,
|
||||
iconPlacement = 'left',
|
||||
label,
|
||||
...rest
|
||||
} = props
|
||||
const { size = '32', icon, iconPlacement = 'left', label, ...rest } = props
|
||||
|
||||
const iconOnly = Boolean(icon && !label)
|
||||
|
||||
|
|
|
@ -8,4 +8,4 @@ export type CustomisationColorType = keyof typeof customisation
|
|||
|
||||
export type Prettify<T> = {
|
||||
[K in keyof T]: T[K]
|
||||
} & {} // eslint-disable-line @typescript-eslint/ban-types
|
||||
} & {}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import js from '@eslint/js'
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
{
|
||||
...js.configs.recommended,
|
||||
files: ['**/*.js', '**/*.mjs', '**/*.cjs'],
|
||||
},
|
||||
]
|
|
@ -1,103 +1,174 @@
|
|||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
// TODO: Enable type-aware linting (https://typescript-eslint.io/docs/linting/type-linting)
|
||||
// "tsconfigRootDir": ".",
|
||||
// "project": ["./packages/*/tsconfig.json"],
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
warnOnUnsupportedTypeScriptVersion: true,
|
||||
// // @ts-check
|
||||
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import {
|
||||
parser as typescriptParser,
|
||||
plugin as typescriptPlugin,
|
||||
configs as typescriptConfigs,
|
||||
} from 'typescript-eslint'
|
||||
import commentsPlugin from 'eslint-plugin-eslint-comments'
|
||||
import * as importPlugin from 'eslint-plugin-import'
|
||||
import jsxA11yPlugin from 'eslint-plugin-jsx-a11y'
|
||||
import reactPlugin from 'eslint-plugin-react'
|
||||
import reactHooksPlugin from 'eslint-plugin-react-hooks'
|
||||
import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort'
|
||||
import prettierPlugin from 'eslint-plugin-prettier/recommended'
|
||||
import tailwindcssPlugin from 'eslint-plugin-tailwindcss'
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
{
|
||||
name: '@status-im/eslint-config',
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
},
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
'import',
|
||||
'simple-import-sort',
|
||||
'react',
|
||||
'jsx-a11y',
|
||||
],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
// "plugin:@typescript-eslint/recommended-requiring-type-checking",
|
||||
'plugin:eslint-comments/recommended',
|
||||
'plugin:import/recommended',
|
||||
'plugin:import/typescript',
|
||||
'plugin:jsx-a11y/recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
'plugin:react/jsx-runtime',
|
||||
'prettier',
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
files: ['examples/**/*.tsx'],
|
||||
rules: {
|
||||
'react/jsx-uses-react': 'off',
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
import: importPlugin,
|
||||
},
|
||||
],
|
||||
rules: {
|
||||
'react/prop-types': 0,
|
||||
// "@typescript-eslint/consistent-type-definitions": ["error", "interface"],
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
// TODO: turn on this rul
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
// "@typescript-eslint/consistent-type-exports": "error",
|
||||
'simple-import-sort/imports': [
|
||||
'error',
|
||||
{
|
||||
groups: [
|
||||
// Side effect imports.
|
||||
['^\\u0000'],
|
||||
// `react` related packages come first.
|
||||
['^react$', '^react-dom$'],
|
||||
// Things that start with a letter (or digit or underscore), or `@` followed by a letter.
|
||||
['^@?\\w'],
|
||||
// Absolute imports and other imports such as Vue-style `@/foo`.
|
||||
// Anything not matched in another group.
|
||||
['^'],
|
||||
// Relative imports.
|
||||
// Anything that starts with a dot.
|
||||
['^\\.'],
|
||||
// type imports last as a separate group
|
||||
['^.+\\u0000$'],
|
||||
],
|
||||
},
|
||||
rules: {
|
||||
...importPlugin.configs.recommended.rules,
|
||||
},
|
||||
files: [
|
||||
'**/*.js',
|
||||
'**/*.cjs',
|
||||
'**/*.mjs',
|
||||
'**/*.jsx',
|
||||
'**/*.ts',
|
||||
'**/*.mts',
|
||||
'**/*.tsx',
|
||||
'**/*.mdx',
|
||||
], // js, ts, mdx
|
||||
},
|
||||
{
|
||||
...js.configs.recommended,
|
||||
files: ['**/*.js', '**/*.mjs', '**/*.cjs', '**/*.ts', '**/*.tsx'], // js
|
||||
},
|
||||
...typescriptConfigs.recommended.map(config => ({
|
||||
...config,
|
||||
files: ['**/*.ts', '**/*.mts', '**/*.tsx'],
|
||||
})),
|
||||
{
|
||||
...jsxA11yPlugin.flatConfigs.recommended,
|
||||
files: ['**/*.js', '**/*.mjs', '**/*.cjs', '**/*.ts', '**/*.tsx'],
|
||||
},
|
||||
{
|
||||
...reactPlugin.configs.flat['jsx-runtime'],
|
||||
files: ['**/*.js', '**/*.mjs', '**/*.cjs', '**/*.ts', '**/*.tsx'],
|
||||
},
|
||||
{
|
||||
...prettierPlugin,
|
||||
files: [
|
||||
'**/*.js',
|
||||
'**/*.mjs',
|
||||
'**/*.cjs',
|
||||
'**/*.ts',
|
||||
'**/*.tsx',
|
||||
'**/*.md',
|
||||
'**/*.mdx',
|
||||
],
|
||||
'simple-import-sort/exports': 'error',
|
||||
'import/first': 'error',
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-duplicates': 'error',
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
'import/resolver': {
|
||||
node: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
project: [
|
||||
'tsconfig.base.json',
|
||||
'packages/*/tsconfig.json',
|
||||
'apps/*/tsconfig.json',
|
||||
],
|
||||
{
|
||||
files: ['**/*.ts', '**/*.mts', '**/*.tsx'], // ts
|
||||
languageOptions: {
|
||||
parser: typescriptParser,
|
||||
parserOptions: {
|
||||
// TODO: Enable type-aware linting (https://typescript-eslint.io/docs/linting/type-linting)
|
||||
// "tsconfigRootDir": ".",
|
||||
// "project": ["./packages/*/tsconfig.json"],
|
||||
// sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
// warnOnUnsupportedTypeScriptVersion: true,
|
||||
},
|
||||
typescript: {
|
||||
alwaysTryTypes: true,
|
||||
project: [
|
||||
'tsconfig.base.json',
|
||||
'packages/*/tsconfig.json',
|
||||
'apps/*/tsconfig.json',
|
||||
],
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
'@typescript-eslint': typescriptPlugin,
|
||||
'eslint-comments': commentsPlugin,
|
||||
react: reactPlugin,
|
||||
'react-hooks': reactHooksPlugin,
|
||||
'simple-import-sort': simpleImportSortPlugin,
|
||||
},
|
||||
rules: {
|
||||
...importPlugin.configs.typescript.rules,
|
||||
...reactHooksPlugin.configs.recommended.rules,
|
||||
'react/prop-types': 0,
|
||||
// "@typescript-eslint/consistent-type-definitions": ["error", "interface"],
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
// TODO: turn on this rul
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
// "@typescript-eslint/consistent-type-exports": "error",
|
||||
'simple-import-sort/imports': [
|
||||
'error',
|
||||
{
|
||||
groups: [
|
||||
// Side effect imports.
|
||||
['^\\u0000'],
|
||||
// `react` related packages come first.
|
||||
['^react$', '^react-dom$'],
|
||||
// Things that start with a letter (or digit or underscore), or `@` followed by a letter.
|
||||
['^@?\\w'],
|
||||
// Absolute imports and other imports such as Vue-style `@/foo`.
|
||||
// Anything not matched in another group.
|
||||
['^'],
|
||||
// Relative imports.
|
||||
// Anything that starts with a dot.
|
||||
['^\\.'],
|
||||
// type imports last as a separate group
|
||||
['^.+\\u0000$'],
|
||||
],
|
||||
},
|
||||
],
|
||||
'simple-import-sort/exports': 'error',
|
||||
'import/first': 'error',
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-duplicates': 'error',
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
'import/resolver': {
|
||||
node: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
project: [
|
||||
'tsconfig.base.json',
|
||||
'packages/*/tsconfig.json',
|
||||
'apps/*/tsconfig.json',
|
||||
],
|
||||
},
|
||||
typescript: {
|
||||
alwaysTryTypes: true,
|
||||
project: [
|
||||
'tsconfig.base.json',
|
||||
'packages/*/tsconfig.json',
|
||||
'apps/*/tsconfig.json',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export const tailwindcssConfigs = [
|
||||
{
|
||||
files: ['**/*.ts', '**/*.mts', '**/*.tsx'],
|
||||
},
|
||||
...tailwindcssPlugin.configs['flat/recommended'],
|
||||
{
|
||||
rules: {
|
||||
'tailwindcss/classnames-order': 'off',
|
||||
'tailwindcss/migration-from-tailwind-2': 'off',
|
||||
},
|
||||
settings: {
|
||||
tailwindcss: {
|
||||
callees: ['cx', 'cva'],
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"version": "1.0.1",
|
||||
"main": "index.js",
|
||||
"license": "MPL-2.0",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./index.js",
|
||||
|
@ -15,23 +16,28 @@
|
|||
},
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"clean": "rimraf node_modules"
|
||||
"clean": "rimraf node_modules",
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^9.14.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.11",
|
||||
"@typescript-eslint/parser": "^5.59.11",
|
||||
"eslint": "^8.42.0",
|
||||
"eslint-config-next": "^13.2.4",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-import-resolver-node": "^0.3.7",
|
||||
"eslint-import-resolver-typescript": "^3.5.5",
|
||||
"@eslint/eslintrc": "^3.1.0",
|
||||
"@eslint/js": "^9.14.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-import-resolver-node": "^0.3.9",
|
||||
"eslint-import-resolver-typescript": "^3.6.3",
|
||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||
"eslint-plugin-tailwindcss": "^3.12.1"
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-react": "^7.37.2",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
"eslint-plugin-tailwindcss": "^3.17.5",
|
||||
"globals": "^15.12.0",
|
||||
"typescript-eslint": "^8.13.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"extends": ["@status-im/eslint-config"],
|
||||
"ignorePatterns": ["dist", "index.js", "index.es.js"]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import configs from '@status-im/eslint-config'
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
...configs,
|
||||
{
|
||||
ignores: ['dist', 'index.js', 'index.es.js'],
|
||||
},
|
||||
]
|
|
@ -62,11 +62,11 @@
|
|||
"generate": "rimraf src && svgr svg --out-dir src && pnpm lint:fix && pnpm format",
|
||||
"dev": "vite build --watch --mode development",
|
||||
"build": "vite build",
|
||||
"postbuild": "pnpm build:types && node --version",
|
||||
"postbuild": "pnpm build:types",
|
||||
"build:types": "tsc src/**/index.ts --emitDeclarationOnly --declaration --jsx react-jsx --skipLibCheck --declarationDir ./dist",
|
||||
"#test": "vitest",
|
||||
"typecheck": "tsc",
|
||||
"lint": "eslint 'src/**/*.{ts,tsx}'",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "pnpm lint --fix",
|
||||
"format": "prettier --write 'src/**/*.{ts,tsx}'",
|
||||
"clean": "rimraf dist node_modules .turbo",
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"extends": ["@status-im/eslint-config"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["./src/protos/**/*_pb.ts"],
|
||||
"rules": {
|
||||
"eslint-comments/disable-enable-pair": "off",
|
||||
"eslint-comments/no-unlimited-disable": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import configs from '@status-im/eslint-config'
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
...configs,
|
||||
{
|
||||
files: ['./src/protos/**/*_pb.ts'],
|
||||
rules: {
|
||||
'eslint-comments/disable-enable-pair': 'off',
|
||||
'eslint-comments/no-unlimited-disable': 'off',
|
||||
},
|
||||
},
|
||||
]
|
|
@ -86,7 +86,7 @@ export class ActivityCenter {
|
|||
|
||||
public addMessageNotification = (
|
||||
newMessage: ChatMessage,
|
||||
referencedMessage?: ChatMessage
|
||||
referencedMessage?: ChatMessage,
|
||||
) => {
|
||||
let isMention: boolean | undefined
|
||||
let isReply: boolean | undefined
|
||||
|
|
|
@ -101,7 +101,7 @@ export class Chat {
|
|||
client: Client,
|
||||
uuid: string,
|
||||
type: MessageType.COMMUNITY_CHAT,
|
||||
description: CommunityChat
|
||||
description: CommunityChat,
|
||||
) => {
|
||||
const id = `${community.publicKey}${uuid}`
|
||||
const contentTopic = idToContentTopic(id)
|
||||
|
@ -171,7 +171,7 @@ export class Chat {
|
|||
}
|
||||
|
||||
public onMessage = (
|
||||
callback: (messages: ChatMessage[]) => void
|
||||
callback: (messages: ChatMessage[]) => void,
|
||||
): (() => void) => {
|
||||
this.messageCallbacks.add(callback)
|
||||
// todo?: set from ui, think use case without an ui
|
||||
|
@ -227,7 +227,7 @@ export class Chat {
|
|||
pageSize: 50,
|
||||
// most recent page first
|
||||
pageDirection: PageDirection.BACKWARD,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
this.#previousFetchedStartTime = startTime
|
||||
|
@ -278,7 +278,7 @@ export class Chat {
|
|||
this.#oldestFetchedMessage = this.getOldestFetchedMessage(
|
||||
this.#oldestFetchedMessage,
|
||||
newMessage.messageId,
|
||||
timestamp
|
||||
timestamp,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -340,7 +340,7 @@ export class Chat {
|
|||
if (!this.#isActive && !isAuthor) {
|
||||
this.client.activityCenter.addMessageNotification(
|
||||
newMessage,
|
||||
this.#messages.get(newMessage.responseTo)
|
||||
this.#messages.get(newMessage.responseTo),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -349,7 +349,7 @@ export class Chat {
|
|||
messageId: string,
|
||||
text: string,
|
||||
clock: bigint,
|
||||
signerPublicKey: string
|
||||
signerPublicKey: string,
|
||||
) => {
|
||||
const message = this.#messages.get(messageId)
|
||||
|
||||
|
@ -374,7 +374,7 @@ export class Chat {
|
|||
public handleDeletedMessage = (
|
||||
messageId: string,
|
||||
clock: bigint,
|
||||
signerPublicKey: string
|
||||
signerPublicKey: string,
|
||||
) => {
|
||||
const message = this.#messages.get(messageId)
|
||||
if (message && this.isAuthor(message, signerPublicKey)) {
|
||||
|
@ -394,7 +394,7 @@ export class Chat {
|
|||
public handlePinnedMessage = (
|
||||
messageId: string,
|
||||
clock: bigint,
|
||||
pinned?: boolean
|
||||
pinned?: boolean,
|
||||
) => {
|
||||
const message = this.#messages.get(messageId)
|
||||
if (message) {
|
||||
|
@ -419,14 +419,14 @@ export class Chat {
|
|||
messageId: string,
|
||||
reaction: EmojiReaction,
|
||||
clock: bigint,
|
||||
signerPublicKey: string
|
||||
signerPublicKey: string,
|
||||
) => {
|
||||
const message = this.#messages.get(messageId)
|
||||
if (message) {
|
||||
const reactions = getReactions(
|
||||
reaction,
|
||||
message.reactions,
|
||||
signerPublicKey
|
||||
signerPublicKey,
|
||||
)
|
||||
message.reactions = reactions
|
||||
|
||||
|
@ -447,7 +447,7 @@ export class Chat {
|
|||
SAD: new Set<string>(),
|
||||
ANGRY: new Set<string>(),
|
||||
},
|
||||
signerPublicKey
|
||||
signerPublicKey,
|
||||
)
|
||||
|
||||
this.#reactEvents.set(messageId, { clock, reactions })
|
||||
|
@ -455,7 +455,7 @@ export class Chat {
|
|||
const reactions = getReactions(
|
||||
reaction,
|
||||
reactEvent.reactions,
|
||||
signerPublicKey
|
||||
signerPublicKey,
|
||||
)
|
||||
|
||||
this.#reactEvents.set(messageId, { clock, reactions })
|
||||
|
@ -489,7 +489,7 @@ export class Chat {
|
|||
ApplicationMetadataMessage_Type.CHAT_MESSAGE,
|
||||
payload,
|
||||
this.contentTopic,
|
||||
this.symmetricKey
|
||||
this.symmetricKey,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -518,7 +518,7 @@ export class Chat {
|
|||
ApplicationMetadataMessage_Type.CHAT_MESSAGE,
|
||||
payload,
|
||||
this.contentTopic,
|
||||
this.symmetricKey
|
||||
this.symmetricKey,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -554,14 +554,14 @@ export class Chat {
|
|||
ApplicationMetadataMessage_Type.EDIT_MESSAGE,
|
||||
payload,
|
||||
this.contentTopic,
|
||||
this.symmetricKey
|
||||
this.symmetricKey,
|
||||
)
|
||||
}
|
||||
|
||||
public deleteMessage = async (messageId: string) => {
|
||||
if (!this.client.account) {
|
||||
throw new Error(
|
||||
'Text message cannot be deleted without a created account'
|
||||
'Text message cannot be deleted without a created account',
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -587,13 +587,13 @@ export class Chat {
|
|||
ApplicationMetadataMessage_Type.DELETE_MESSAGE,
|
||||
payload,
|
||||
this.contentTopic,
|
||||
this.symmetricKey
|
||||
this.symmetricKey,
|
||||
)
|
||||
}
|
||||
|
||||
public sendReaction = async (
|
||||
messageId: string,
|
||||
reaction: keyof ChatMessage['reactions']
|
||||
reaction: keyof ChatMessage['reactions'],
|
||||
) => {
|
||||
if (!this.client.account) {
|
||||
throw new Error('Account not initialized')
|
||||
|
@ -606,7 +606,7 @@ export class Chat {
|
|||
}
|
||||
|
||||
const retracted = message.reactions[reaction].has(
|
||||
`0x${this.client.account.publicKey}`
|
||||
`0x${this.client.account.publicKey}`,
|
||||
)
|
||||
|
||||
const payload = new EmojiReaction({
|
||||
|
@ -623,13 +623,13 @@ export class Chat {
|
|||
ApplicationMetadataMessage_Type.EMOJI_REACTION,
|
||||
payload,
|
||||
this.contentTopic,
|
||||
this.symmetricKey
|
||||
this.symmetricKey,
|
||||
)
|
||||
}
|
||||
|
||||
public isAuthor = (
|
||||
message: ChatMessage,
|
||||
signerPublicKey: string
|
||||
signerPublicKey: string,
|
||||
): boolean => {
|
||||
return message.signer === signerPublicKey
|
||||
}
|
||||
|
@ -637,7 +637,7 @@ export class Chat {
|
|||
private getOldestFetchedMessage(
|
||||
oldestMessage: FetchedMessage | undefined,
|
||||
messageId: string,
|
||||
messageTimestamp?: Date
|
||||
messageTimestamp?: Date,
|
||||
): FetchedMessage {
|
||||
let message: FetchedMessage
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ class Client {
|
|||
await waitForRemotePeer(
|
||||
waku,
|
||||
[Protocols.Store, Protocols.Filter, Protocols.LightPush],
|
||||
10 * 1000
|
||||
10 * 1000,
|
||||
)
|
||||
|
||||
// Client
|
||||
|
@ -250,7 +250,7 @@ class Client {
|
|||
type: ApplicationMetadataMessage_Type,
|
||||
payload: Uint8Array,
|
||||
contentTopic: string,
|
||||
symKey: Uint8Array
|
||||
symKey: Uint8Array,
|
||||
) => {
|
||||
if (!this.waku) {
|
||||
throw new Error('Waku not started')
|
||||
|
@ -278,7 +278,7 @@ class Client {
|
|||
shard: 32,
|
||||
},
|
||||
}),
|
||||
{ payload: message }
|
||||
{ payload: message },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ export class Community {
|
|||
if (this.description) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
return this.description
|
||||
|
@ -120,12 +120,12 @@ export class Community {
|
|||
shard: 32,
|
||||
}),
|
||||
],
|
||||
this.client.handleWakuMessage
|
||||
this.client.handleWakuMessage,
|
||||
)
|
||||
}
|
||||
|
||||
private observeChatMessages = async (
|
||||
chatDescriptions: CommunityDescription['chats']
|
||||
chatDescriptions: CommunityDescription['chats'],
|
||||
) => {
|
||||
const chatPromises = Object.entries(chatDescriptions).map(
|
||||
async ([chatUuid, chatDescription]: [string, CommunityChat]) => {
|
||||
|
@ -134,7 +134,7 @@ export class Community {
|
|||
this.client,
|
||||
chatUuid,
|
||||
MessageType.COMMUNITY_CHAT,
|
||||
chatDescription
|
||||
chatDescription,
|
||||
)
|
||||
|
||||
this.chats.set(chatUuid, chat)
|
||||
|
@ -146,18 +146,18 @@ export class Community {
|
|||
shard: 32,
|
||||
}),
|
||||
],
|
||||
this.client.handleWakuMessage
|
||||
this.client.handleWakuMessage,
|
||||
)
|
||||
|
||||
this.#chatUnobserveFns.set(chat.contentTopic, unobserveFn)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
await Promise.all(chatPromises)
|
||||
}
|
||||
|
||||
private unobserveChatMessages = (
|
||||
chatDescription: CommunityDescription['chats']
|
||||
chatDescription: CommunityDescription['chats'],
|
||||
) => {
|
||||
const contentTopics: string[] = []
|
||||
|
||||
|
@ -179,7 +179,7 @@ export class Community {
|
|||
}
|
||||
|
||||
contentTopics.forEach(contentTopic =>
|
||||
this.#chatUnobserveFns.get(contentTopic)?.()
|
||||
this.#chatUnobserveFns.get(contentTopic)?.(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -207,7 +207,7 @@ export class Community {
|
|||
// observe
|
||||
const removedChats = getDifferenceByKeys(
|
||||
this.description.chats,
|
||||
description.chats
|
||||
description.chats,
|
||||
)
|
||||
if (Object.keys(removedChats).length) {
|
||||
this.unobserveChatMessages(removedChats)
|
||||
|
@ -215,7 +215,7 @@ export class Community {
|
|||
|
||||
const addedChats = getDifferenceByKeys(
|
||||
description.chats,
|
||||
this.description.chats
|
||||
this.description.chats,
|
||||
)
|
||||
if (Object.keys(addedChats).length) {
|
||||
this.observeChatMessages(addedChats)
|
||||
|
@ -232,7 +232,7 @@ export class Community {
|
|||
|
||||
const members = getObjectsDifference(
|
||||
this.description.members,
|
||||
description.members
|
||||
description.members,
|
||||
)
|
||||
|
||||
this.addMembers(members.added)
|
||||
|
@ -251,7 +251,7 @@ export class Community {
|
|||
// handle
|
||||
Object.entries(this.description.chats).forEach(
|
||||
([chatUuid, chatDescription]) =>
|
||||
this.chats.get(chatUuid)?.handleChange(chatDescription)
|
||||
this.chats.get(chatUuid)?.handleChange(chatDescription),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -275,13 +275,13 @@ export class Community {
|
|||
ApplicationMetadataMessage_Type.COMMUNITY_REQUEST_TO_JOIN,
|
||||
payload,
|
||||
this.contentTopic,
|
||||
this.symmetricKey
|
||||
this.symmetricKey,
|
||||
)
|
||||
}
|
||||
|
||||
public isOwner = (
|
||||
/** Uncompressed. */
|
||||
signerPublicKey: string
|
||||
signerPublicKey: string,
|
||||
): boolean => {
|
||||
return this.publicKey === `0x${compressPublicKey(signerPublicKey)}`
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ export type Reactions = {
|
|||
export function getReactions(
|
||||
reaction: EmojiReaction,
|
||||
reactions: Reactions,
|
||||
publicKey: string
|
||||
publicKey: string,
|
||||
): Reactions {
|
||||
const { type, retracted } = reaction
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ export function handleWakuMessage(
|
|||
// state
|
||||
client: Client,
|
||||
community: Community,
|
||||
account?: Account
|
||||
account?: Account,
|
||||
): void {
|
||||
// decode (layers)
|
||||
// validate
|
||||
|
@ -57,9 +57,8 @@ export function handleWakuMessage(
|
|||
if (decodedProtocol) {
|
||||
messageToDecode = decodedProtocol.publicMessage
|
||||
}
|
||||
} catch {
|
||||
// eslint-disable-next-line no-empty
|
||||
}
|
||||
} catch {}
|
||||
|
||||
const decodedMetadata = ApplicationMetadataMessage.fromBinary(messageToDecode)
|
||||
if (!decodedMetadata.payload) {
|
||||
|
@ -69,12 +68,12 @@ export function handleWakuMessage(
|
|||
|
||||
const signerPublicKeyBytes = recoverPublicKey(
|
||||
decodedMetadata.signature,
|
||||
decodedMetadata.payload
|
||||
decodedMetadata.payload,
|
||||
)
|
||||
|
||||
const messageId = payloadToId(
|
||||
decodedProtocol?.publicMessage ?? wakuMessage.payload,
|
||||
signerPublicKeyBytes
|
||||
signerPublicKeyBytes,
|
||||
)
|
||||
const messageTimestamp = wakuMessage.timestamp
|
||||
const signerPublicKey = `0x${bytesToHex(signerPublicKeyBytes)}`
|
||||
|
@ -181,7 +180,7 @@ export function handleWakuMessage(
|
|||
messageId,
|
||||
decodedPayload.text,
|
||||
decodedPayload.clock,
|
||||
signerPublicKey
|
||||
signerPublicKey,
|
||||
)
|
||||
chat.setClock(decodedPayload.clock)
|
||||
|
||||
|
@ -220,7 +219,7 @@ export function handleWakuMessage(
|
|||
chat.handleDeletedMessage(
|
||||
messageId,
|
||||
decodedPayload.clock,
|
||||
signerPublicKey
|
||||
signerPublicKey,
|
||||
)
|
||||
chat.setClock(decodedPayload.clock)
|
||||
|
||||
|
@ -259,7 +258,7 @@ export function handleWakuMessage(
|
|||
chat.handlePinnedMessage(
|
||||
messageId,
|
||||
decodedPayload.clock,
|
||||
decodedPayload.pinned
|
||||
decodedPayload.pinned,
|
||||
)
|
||||
chat.setClock(decodedPayload.clock)
|
||||
|
||||
|
@ -299,7 +298,7 @@ export function handleWakuMessage(
|
|||
messageId,
|
||||
decodedPayload,
|
||||
decodedPayload.clock,
|
||||
signerPublicKey
|
||||
signerPublicKey,
|
||||
)
|
||||
chat.setClock(decodedPayload.clock)
|
||||
|
||||
|
@ -320,7 +319,6 @@ export function handleWakuMessage(
|
|||
}
|
||||
} catch {
|
||||
// protons-runtime throws when trying to decode invalid protocol buffers
|
||||
// eslint-disable-next-line no-empty
|
||||
}
|
||||
|
||||
return
|
||||
|
|
|
@ -4,10 +4,10 @@ import {
|
|||
} from '../../protos/communities_pb'
|
||||
|
||||
export function isEncrypted(
|
||||
tokenPermissions: CommunityDescription['tokenPermissions']
|
||||
tokenPermissions: CommunityDescription['tokenPermissions'],
|
||||
): boolean {
|
||||
return Object.values(tokenPermissions).some(
|
||||
permission =>
|
||||
permission.type === CommunityTokenPermission_Type.BECOME_MEMBER
|
||||
permission.type === CommunityTokenPermission_Type.BECOME_MEMBER,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ export function mapChatMessage(
|
|||
signerPublicKey: string
|
||||
community: Community
|
||||
chat: Chat
|
||||
}
|
||||
},
|
||||
): ChatMessage {
|
||||
const { messageId, chatUuid, signerPublicKey, community, chat } = props
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ export class LocalStorage implements Storage {
|
|||
try {
|
||||
window.localStorage.setItem(
|
||||
this.#getStorageKey(key),
|
||||
JSON.stringify(value)
|
||||
JSON.stringify(value),
|
||||
)
|
||||
return true
|
||||
} catch {
|
||||
|
|
|
@ -6,14 +6,14 @@ export const pbkdf2: PBKDF2 = async (
|
|||
password: Uint8Array,
|
||||
salt: Uint8Array,
|
||||
iterations: number,
|
||||
keylen: number
|
||||
keylen: number,
|
||||
): Promise<Uint8Array> => {
|
||||
const cryptoKey = await window.crypto.subtle.importKey(
|
||||
'raw',
|
||||
password,
|
||||
{ name: 'PBKDF2' },
|
||||
false,
|
||||
['deriveBits']
|
||||
['deriveBits'],
|
||||
)
|
||||
|
||||
const derivedKey = await window.crypto.subtle.deriveBits(
|
||||
|
@ -26,7 +26,7 @@ export const pbkdf2: PBKDF2 = async (
|
|||
},
|
||||
},
|
||||
cryptoKey,
|
||||
keylen << 3
|
||||
keylen << 3,
|
||||
)
|
||||
|
||||
return new Uint8Array(derivedKey)
|
||||
|
|
|
@ -16,7 +16,7 @@ export class EthereumClient {
|
|||
|
||||
async resolvePublicKey(
|
||||
ensName: string,
|
||||
options: { compress: boolean }
|
||||
options: { compress: boolean },
|
||||
): Promise<string | undefined> {
|
||||
try {
|
||||
const resolver = await this.#provider.getResolver(ensName)
|
||||
|
@ -51,22 +51,22 @@ export class EthereumClient {
|
|||
|
||||
async resolveOwner(
|
||||
registryContractAddress: string,
|
||||
communityPublicKey: string
|
||||
communityPublicKey: string,
|
||||
): Promise<string | undefined> {
|
||||
try {
|
||||
const registryContract = new ethers.Contract(
|
||||
registryContractAddress,
|
||||
['function getEntry(address _communityAddress) view returns (address)'],
|
||||
this.#provider
|
||||
this.#provider,
|
||||
)
|
||||
const ownerContractAddress = await registryContract.getEntry(
|
||||
publicKeyToETHAddress(communityPublicKey)
|
||||
publicKeyToETHAddress(communityPublicKey),
|
||||
)
|
||||
|
||||
const ownerContract = new ethers.Contract(
|
||||
ownerContractAddress,
|
||||
['function signerPublicKey() view returns (bytes)'],
|
||||
this.#provider
|
||||
this.#provider,
|
||||
)
|
||||
const owner = await ownerContract.signerPublicKey()
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export function getDifferenceByKeys<T extends Record<string, unknown>>(
|
||||
a: T,
|
||||
b: T
|
||||
b: T,
|
||||
): T {
|
||||
const initialValue: Record<string, unknown> = {}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ type Input<Value> = Record<string, Value>
|
|||
|
||||
export function getObjectsDifference<Value>(
|
||||
oldObject: Input<Value>,
|
||||
newObject: Input<Value>
|
||||
newObject: Input<Value>,
|
||||
) {
|
||||
const added: Record<string, Value> = {}
|
||||
const removed: string[] = []
|
||||
|
|
|
@ -16,7 +16,7 @@ export type ChannelInfo = {
|
|||
|
||||
export function mapChannel(
|
||||
communityChat: CommunityChat,
|
||||
communityDescription: CommunityDescription
|
||||
communityDescription: CommunityDescription,
|
||||
): ChannelInfo | undefined {
|
||||
const community = mapCommunity(communityDescription)
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ export type Tag = {
|
|||
}
|
||||
|
||||
export function mapCommunity(
|
||||
communityDescription: CommunityDescription
|
||||
communityDescription: CommunityDescription,
|
||||
): CommunityInfo | undefined {
|
||||
const { identity, tags, members } = communityDescription
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ export type UserInfo = {
|
|||
|
||||
export function mapUser(
|
||||
contactCodeAdvertisement: ContactCodeAdvertisement,
|
||||
userPublicKey: string
|
||||
userPublicKey: string,
|
||||
): UserInfo | undefined {
|
||||
const { chatIdentity: identity } = contactCodeAdvertisement
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ class RequestClient {
|
|||
contractAddresses?: Record<number, Record<string, string>>
|
||||
started?: boolean
|
||||
environment?: 'development' | 'preview' | 'production'
|
||||
}
|
||||
},
|
||||
) {
|
||||
const { environment = 'development' } = options
|
||||
|
||||
|
@ -136,7 +136,7 @@ class RequestClient {
|
|||
await Promise.all([
|
||||
async () => this.waku.stop(),
|
||||
[...this.#ethereumClients.values()].map(async provider =>
|
||||
provider.stop()
|
||||
provider.stop(),
|
||||
),
|
||||
])
|
||||
|
||||
|
@ -163,7 +163,7 @@ class RequestClient {
|
|||
|
||||
public fetchCommunity = async (
|
||||
/** Compressed */
|
||||
publicKey: string
|
||||
publicKey: string,
|
||||
): Promise<CommunityInfo | undefined> => {
|
||||
const communityDescription = await this.fetchCommunityDescription(publicKey)
|
||||
|
||||
|
@ -177,7 +177,7 @@ class RequestClient {
|
|||
public fetchChannel = async (
|
||||
/** Compressed */
|
||||
publicKey: string,
|
||||
uuid: string
|
||||
uuid: string,
|
||||
): Promise<ChannelInfo | undefined> => {
|
||||
const communityDescription = await this.fetchCommunityDescription(publicKey)
|
||||
|
||||
|
@ -192,11 +192,10 @@ class RequestClient {
|
|||
|
||||
public fetchUser = async (
|
||||
/** Uncompressed */
|
||||
publicKey: string
|
||||
publicKey: string,
|
||||
): Promise<UserInfo | undefined> => {
|
||||
const contactCodeAdvertisement = await this.fetchContactCodeAdvertisement(
|
||||
publicKey
|
||||
)
|
||||
const contactCodeAdvertisement =
|
||||
await this.fetchContactCodeAdvertisement(publicKey)
|
||||
|
||||
if (!contactCodeAdvertisement) {
|
||||
return
|
||||
|
@ -207,7 +206,7 @@ class RequestClient {
|
|||
|
||||
public fetchCommunityDescription = async (
|
||||
/** Compressed */
|
||||
communityPublicKey: string
|
||||
communityPublicKey: string,
|
||||
): Promise<CommunityDescription | undefined> => {
|
||||
const contentTopic = idToContentTopic(communityPublicKey)
|
||||
const symmetricKey = await generateKeyFromPassword(communityPublicKey)
|
||||
|
@ -238,24 +237,25 @@ class RequestClient {
|
|||
|
||||
// decode
|
||||
const decodedCommunityDescription = CommunityDescription.fromBinary(
|
||||
message.payload
|
||||
message.payload,
|
||||
)
|
||||
|
||||
// validate
|
||||
if (
|
||||
!isClockValid(
|
||||
BigInt(decodedCommunityDescription.clock),
|
||||
message.timestamp
|
||||
message.timestamp,
|
||||
)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
const ownerTokenPermission = Object.values(
|
||||
decodedCommunityDescription.tokenPermissions
|
||||
decodedCommunityDescription.tokenPermissions,
|
||||
).find(
|
||||
permission =>
|
||||
permission.type === CommunityTokenPermission_Type.BECOME_TOKEN_OWNER
|
||||
permission.type ===
|
||||
CommunityTokenPermission_Type.BECOME_TOKEN_OWNER,
|
||||
)
|
||||
if (ownerTokenPermission) {
|
||||
const criteria = ownerTokenPermission.tokenCriteria[0]
|
||||
|
@ -281,7 +281,7 @@ class RequestClient {
|
|||
const ownerPublicKey = await ethereumClient.resolveOwner(
|
||||
this.#contractAddresses[Number(chainId)]
|
||||
.CommunityOwnerTokenRegistry,
|
||||
communityPublicKey
|
||||
communityPublicKey,
|
||||
)
|
||||
|
||||
if (ownerPublicKey !== message.signerPublicKey) {
|
||||
|
@ -301,11 +301,11 @@ class RequestClient {
|
|||
}
|
||||
|
||||
private fetchContactCodeAdvertisement = async (
|
||||
publicKey: string
|
||||
publicKey: string,
|
||||
): Promise<ContactCodeAdvertisement | undefined> => {
|
||||
const contentTopic = idToContentTopic(`${publicKey}-contact-code`)
|
||||
const symmetricKey = await generateKeyFromPassword(
|
||||
`${publicKey}-contact-code`
|
||||
`${publicKey}-contact-code`,
|
||||
)
|
||||
|
||||
const wakuMessageGenerator = this.waku.store.queryGenerator([
|
||||
|
@ -336,7 +336,7 @@ class RequestClient {
|
|||
|
||||
// decode
|
||||
const decodedContactCode = ContactCodeAdvertisement.fromBinary(
|
||||
message.payload
|
||||
message.payload,
|
||||
)
|
||||
|
||||
// validate
|
||||
|
@ -347,7 +347,7 @@ class RequestClient {
|
|||
if (
|
||||
!isClockValid(
|
||||
BigInt(decodedContactCode.chatIdentity.clock),
|
||||
message.timestamp
|
||||
message.timestamp,
|
||||
)
|
||||
) {
|
||||
continue
|
||||
|
@ -364,7 +364,7 @@ class RequestClient {
|
|||
}
|
||||
|
||||
private handleWakuMessage = (
|
||||
wakuMessage: DecodedMessage
|
||||
wakuMessage: DecodedMessage,
|
||||
):
|
||||
| {
|
||||
timestamp: Date
|
||||
|
@ -394,17 +394,17 @@ class RequestClient {
|
|||
|
||||
if (decodedSegment) {
|
||||
const unsegmentedMessageHash = bytesToHex(
|
||||
decodedSegment.entireMessageHash
|
||||
decodedSegment.entireMessageHash,
|
||||
)
|
||||
|
||||
const segmentedWakuMessages = this.#segmentedWakuMessages.get(
|
||||
unsegmentedMessageHash
|
||||
unsegmentedMessageHash,
|
||||
)
|
||||
|
||||
if (!segmentedWakuMessages) {
|
||||
this.#segmentedWakuMessages.set(
|
||||
unsegmentedMessageHash,
|
||||
new Map([[decodedSegment.index, decodedSegment]])
|
||||
new Map([[decodedSegment.index, decodedSegment]]),
|
||||
)
|
||||
|
||||
return
|
||||
|
@ -430,13 +430,12 @@ class RequestClient {
|
|||
messageToDecode = unsegmentedPayload
|
||||
|
||||
this.#segmentedWakuMessages.delete(unsegmentedMessageHash)
|
||||
} catch (error) {
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// eslint-disable-next-line no-empty
|
||||
}
|
||||
} catch {}
|
||||
|
||||
let decodedProtocol
|
||||
try {
|
||||
|
@ -447,9 +446,8 @@ class RequestClient {
|
|||
} else if (decodedProtocol) {
|
||||
messageToDecode = decodedProtocol.publicMessage
|
||||
}
|
||||
} catch {
|
||||
// eslint-disable-next-line no-empty
|
||||
}
|
||||
} catch {}
|
||||
|
||||
let decodedMetadata
|
||||
try {
|
||||
|
@ -468,12 +466,12 @@ class RequestClient {
|
|||
|
||||
const signerPublicKeyBytes = recoverPublicKey(
|
||||
decodedMetadata.signature,
|
||||
decodedMetadata.payload
|
||||
decodedMetadata.payload,
|
||||
)
|
||||
|
||||
const messageId = payloadToId(
|
||||
decodedProtocol?.publicMessage ?? wakuMessage.payload,
|
||||
signerPublicKeyBytes
|
||||
signerPublicKeyBytes,
|
||||
)
|
||||
|
||||
// already handled
|
||||
|
@ -493,7 +491,7 @@ class RequestClient {
|
|||
}
|
||||
|
||||
export async function createRequestClient(
|
||||
options: RequestClientOptions
|
||||
options: RequestClientOptions,
|
||||
): Promise<RequestClient> {
|
||||
return await RequestClient.start(options)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ export function compressPublicKey(publicKey: string): string {
|
|||
try {
|
||||
const pk = publicKey.replace(/^0[xX]/, '') // ensures hexadecimal digits without "base prefix"
|
||||
return secp.Point.fromHex(pk).toHex(true)
|
||||
} catch (error) {
|
||||
} catch {
|
||||
throw new Error('Invalid public key')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ describe('Create URLs', () => {
|
|||
} as unknown as CommunityDescription
|
||||
|
||||
expect(createCommunityURLWithChatKey(community.chatKey).toString()).toBe(
|
||||
'https://status.app/c#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11'
|
||||
'https://status.app/c#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11',
|
||||
)
|
||||
expect(
|
||||
(
|
||||
|
@ -58,11 +58,11 @@ describe('Create URLs', () => {
|
|||
membersCount: 446_744,
|
||||
tagIndices: [1, 33, 51],
|
||||
},
|
||||
community.chatKey
|
||||
community.chatKey,
|
||||
)
|
||||
).toString()
|
||||
).toString(),
|
||||
).toBe(
|
||||
'https://status.app/c/iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11'
|
||||
'https://status.app/c/iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11',
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -95,9 +95,9 @@ describe('Create URLs', () => {
|
|||
} as unknown as CommunityChat
|
||||
|
||||
expect(
|
||||
createChannelURLWithChatKey(chat.uuid, community.chatKey).toString()
|
||||
createChannelURLWithChatKey(chat.uuid, community.chatKey).toString(),
|
||||
).toBe(
|
||||
'https://status.app/cc/003cdcd5-e065-48f9-b166-b1a94ac75a11#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11'
|
||||
'https://status.app/cc/003cdcd5-e065-48f9-b166-b1a94ac75a11#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11',
|
||||
)
|
||||
expect(
|
||||
(
|
||||
|
@ -112,11 +112,11 @@ describe('Create URLs', () => {
|
|||
displayName: community.description.identity!.displayName,
|
||||
},
|
||||
} as unknown as PlainMessage<ChannelProto>,
|
||||
community.chatKey
|
||||
community.chatKey,
|
||||
)
|
||||
).toString()
|
||||
).toString(),
|
||||
).toBe(
|
||||
'https://status.app/cc/G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11'
|
||||
'https://status.app/cc/G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=#zQ3shYSHp7GoiXaauJMnDcjwU2yNjdzpXLosAWapPS4CFxc11',
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -134,10 +134,10 @@ describe('Create URLs', () => {
|
|||
} as unknown as ContactCodeAdvertisement
|
||||
|
||||
expect(createUserURLWithENS(account.ensName).toString()).toBe(
|
||||
'https://status.app/u#testing.stateofus.eth'
|
||||
'https://status.app/u#testing.stateofus.eth',
|
||||
)
|
||||
expect(createUserURLWithChatKey(account.chatKey).toString()).toBe(
|
||||
'https://status.app/u#zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj'
|
||||
'https://status.app/u#zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj',
|
||||
)
|
||||
expect(
|
||||
(
|
||||
|
@ -147,11 +147,11 @@ describe('Create URLs', () => {
|
|||
displayName: account.description.chatIdentity!.displayName,
|
||||
color: account.description.chatIdentity!.color,
|
||||
},
|
||||
account.chatKey
|
||||
account.chatKey,
|
||||
)
|
||||
).toString()
|
||||
).toString(),
|
||||
).toBe(
|
||||
'https://status.app/u/G10A4B0JdgwyRww90WXtnP1oNH1ZLQNM0yX0Ja9YyAMjrqSZIYINOHCbFhrnKRAcPGStPxCMJDSZlGCKzmZrJcimHY8BbcXlORrElv_BbQEegnMDPx1g9C5VVNl0fE4y#zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj'
|
||||
'https://status.app/u/G10A4B0JdgwyRww90WXtnP1oNH1ZLQNM0yX0Ja9YyAMjrqSZIYINOHCbFhrnKRAcPGStPxCMJDSZlGCKzmZrJcimHY8BbcXlORrElv_BbQEegnMDPx1g9C5VVNl0fE4y#zQ3shwQPhRuDJSjVGVBnTjCdgXy5i9WQaeVPdGJD6yTarJQSj',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -15,7 +15,7 @@ export function createCommunityURLWithChatKey(communityChatKey: string): URL {
|
|||
|
||||
export async function createCommunityURLWithData(
|
||||
communityData: PlainMessage<Community>,
|
||||
communityChatKey: string
|
||||
communityChatKey: string,
|
||||
): Promise<URL> {
|
||||
const encodedURLData = encodeCommunityURLData(communityData)
|
||||
|
||||
|
@ -24,14 +24,14 @@ export async function createCommunityURLWithData(
|
|||
|
||||
export function createChannelURLWithChatKey(
|
||||
channelUuid: string,
|
||||
communityChatKey: string
|
||||
communityChatKey: string,
|
||||
): URL {
|
||||
return new URL(`${BASE_URL}/cc/${channelUuid}#${communityChatKey}`)
|
||||
}
|
||||
|
||||
export async function createChannelURLWithData(
|
||||
channelData: PlainMessage<Channel>,
|
||||
communityChatKey: string
|
||||
communityChatKey: string,
|
||||
): Promise<URL> {
|
||||
const encodedURLData = encodeChannelURLData(channelData)
|
||||
|
||||
|
@ -48,7 +48,7 @@ export function createUserURLWithChatKey(chatKey: string): URL {
|
|||
|
||||
export async function createUserURLWithData(
|
||||
userData: PlainMessage<User>,
|
||||
userChatKey: string
|
||||
userChatKey: string,
|
||||
): Promise<URL> {
|
||||
const encodedURLData = encodeUserURLData(userData)
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ export function decompressPublicKey(publicKey: string): string {
|
|||
try {
|
||||
const pk = publicKey.replace(/^0[xX]/, '') // ensures hexadecimal digits without "base prefix"
|
||||
return secp.Point.fromHex(pk).toHex()
|
||||
} catch (error) {
|
||||
} catch {
|
||||
throw new Error('Invalid public key')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,42 +4,42 @@ import { deserializePublicKey } from './deserialize-public-key'
|
|||
|
||||
test('should deserialize public key from compressed base58btc encoding', () => {
|
||||
expect(
|
||||
deserializePublicKey('zQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU')
|
||||
deserializePublicKey('zQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU'),
|
||||
).toEqual(
|
||||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133'
|
||||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133',
|
||||
)
|
||||
})
|
||||
|
||||
test('should deserialize public key from compressed hexadecimal encoding', () => {
|
||||
expect(
|
||||
deserializePublicKey(
|
||||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133'
|
||||
)
|
||||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133',
|
||||
),
|
||||
).toEqual(
|
||||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133'
|
||||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133',
|
||||
)
|
||||
})
|
||||
|
||||
test('should deserialize public key from uncompressed hexadecimal encoding', () => {
|
||||
expect(
|
||||
deserializePublicKey(
|
||||
'0x049f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb454295513305b23fcf11d005ee622144fc402b713a8928f80d705781e2e78d701c6e01bfc4'
|
||||
)
|
||||
'0x049f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb454295513305b23fcf11d005ee622144fc402b713a8928f80d705781e2e78d701c6e01bfc4',
|
||||
),
|
||||
).toEqual(
|
||||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133'
|
||||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133',
|
||||
)
|
||||
})
|
||||
|
||||
test('should throw when deserializing unsupported multibase encoding', () => {
|
||||
expect(() =>
|
||||
deserializePublicKey('ZQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU')
|
||||
deserializePublicKey('ZQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU'),
|
||||
).toThrowError()
|
||||
})
|
||||
|
||||
test('should throw when deserializing invalid public key', () => {
|
||||
expect(() =>
|
||||
deserializePublicKey(
|
||||
'0x019f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133'
|
||||
)
|
||||
'0x019f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133',
|
||||
),
|
||||
).toThrowError()
|
||||
})
|
||||
|
|
|
@ -30,7 +30,7 @@ type MulticodecCode = (typeof VALID_MULTICODEC_CODES)[number]
|
|||
*/
|
||||
export function deserializePublicKey(
|
||||
publicKey: string, // uncompressed, compressed, or compressed & encoded
|
||||
options = { compress: true }
|
||||
options = { compress: true },
|
||||
): string {
|
||||
const multibasePublicKey = publicKey.replace(/^0[xX]/, 'f') // ensure multibase code for hexadecimal encoding
|
||||
const multibaseCode = multibasePublicKey[0] as MultibaseCode
|
||||
|
@ -52,7 +52,7 @@ export function deserializePublicKey(
|
|||
}
|
||||
|
||||
hexadecimalPublicKey = toHex(
|
||||
base58btcPublicKey.slice(multicodecCodeByteLength)
|
||||
base58btcPublicKey.slice(multicodecCodeByteLength),
|
||||
)
|
||||
|
||||
break
|
||||
|
|
|
@ -27,7 +27,7 @@ describe('Encode URL data', () => {
|
|||
const decodedData = decodeCommunityURLData(encodedData)
|
||||
|
||||
expect(encodedData).toBe(
|
||||
'G8QAgC0OzDOfHB4N5V1zajCKmHvbUAXB6XK6XYLS60WrOmCEEVgFEJaHsLkpTevR-XHc03r4B2pKTOoYJwqbLrLw9u2DhyzlK5rEWE09Dy7oPbVSPhwlOKozCQuAsMX84eJimcwKWNer82gPcCrbhPM-Zx1s3-glfEojrEYRDp61MM2DTNiD92_BDIN3eYvvcQsfT-quKYmaf1_i9Kpzk0Fi'
|
||||
'G8QAgC0OzDOfHB4N5V1zajCKmHvbUAXB6XK6XYLS60WrOmCEEVgFEJaHsLkpTevR-XHc03r4B2pKTOoYJwqbLrLw9u2DhyzlK5rEWE09Dy7oPbVSPhwlOKozCQuAsMX84eJimcwKWNer82gPcCrbhPM-Zx1s3-glfEojrEYRDp61MM2DTNiD92_BDIN3eYvvcQsfT-quKYmaf1_i9Kpzk0Fi',
|
||||
)
|
||||
expect(decodedData).toEqual(data)
|
||||
})
|
||||
|
@ -73,12 +73,12 @@ describe('Encode URL data', () => {
|
|||
}
|
||||
|
||||
const encodedData = encodeChannelURLData(
|
||||
data as unknown as PlainMessage<Channel>
|
||||
data as unknown as PlainMessage<Channel>,
|
||||
)
|
||||
const decodedData = decodeChannelURLData(encodedData)
|
||||
|
||||
expect(encodedData).toBe(
|
||||
'GxoBQCwO7MbOG73h9C_ECmmNLFveFT5wVETFRTal3e2y0Xyou1sfFAV-SsZH0MTwwDRpTuEnp26giuDkQ9algElBJsdfwJYmFggG1GoJJJjnNgaO49Oj0C6qYIaxnbTEvF-6xH6jxmPg5oHSFAguuFhgFpIIby42hURPGM87X47XATSzJGec5_OsF9ZthVfGzWIIRgcltFjTBbPZTiKBcdj_5iQ5DTbPW4LaTsu46RK2OuuSPOXd-ddgstj0g6uYHm2WBUDBjYa1oPniW2ZdVpFpY-ubJq587eM-JytEhXc_Kuq8tiU='
|
||||
'GxoBQCwO7MbOG73h9C_ECmmNLFveFT5wVETFRTal3e2y0Xyou1sfFAV-SsZH0MTwwDRpTuEnp26giuDkQ9algElBJsdfwJYmFggG1GoJJJjnNgaO49Oj0C6qYIaxnbTEvF-6xH6jxmPg5oHSFAguuFhgFpIIby42hURPGM87X47XATSzJGec5_OsF9ZthVfGzWIIRgcltFjTBbPZTiKBcdj_5iQ5DTbPW4LaTsu46RK2OuuSPOXd-ddgstj0g6uYHm2WBUDBjYa1oPniW2ZdVpFpY-ubJq587eM-JytEhXc_Kuq8tiU=',
|
||||
)
|
||||
expect(decodedData).toEqual(data)
|
||||
})
|
||||
|
@ -150,7 +150,7 @@ describe('Encode URL data', () => {
|
|||
const decodedData = decodeUserURLData(encodedData)
|
||||
|
||||
expect(encodedData).toBe(
|
||||
'GxgBoJwHdsOLl4DWt55mGELN6clGsb1UKTEkT0KUMDfwhWFpUyWH_cefTnvlcSf2JUXCOAWoY5ywzry-LnJ-PjgOGT1Pkb8riQp7ghv6Zu-x70x4m8lncZaRWpDN-sEfT85idUCWvppT_QFNa2A6J3Gr69UJGvWmL3S4DBwX2Jr7LBTNOvFPo6lejNUb-xizlAMUTrokunCH-qNmgtU6UK0J6Vkn8Ce35XGBFObxpxnAtnC_J_D-SrBCBnjiUlwH0ViNr3lHBg=='
|
||||
'GxgBoJwHdsOLl4DWt55mGELN6clGsb1UKTEkT0KUMDfwhWFpUyWH_cefTnvlcSf2JUXCOAWoY5ywzry-LnJ-PjgOGT1Pkb8riQp7ghv6Zu-x70x4m8lncZaRWpDN-sEfT85idUCWvppT_QFNa2A6J3Gr69UJGvWmL3S4DBwX2Jr7LBTNOvFPo6lejNUb-xizlAMUTrokunCH-qNmgtU6UK0J6Vkn8Ce35XGBFObxpxnAtnC_J_D-SrBCBnjiUlwH0ViNr3lHBg==',
|
||||
)
|
||||
expect(decodedData).toEqual(data)
|
||||
})
|
||||
|
|
|
@ -8,7 +8,7 @@ test('should create symmetric key from password', async () => {
|
|||
const symKey = await generateKeyFromPassword(password)
|
||||
|
||||
expect(bytesToHex(symKey)).toEqual(
|
||||
'c49ad65ebf2a7b7253bf400e3d27719362a91b2c9b9f54d50a69117021666c33'
|
||||
'c49ad65ebf2a7b7253bf400e3d27719362a91b2c9b9f54d50a69117021666c33',
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -18,6 +18,6 @@ test('should generate symmetric key from chat ID', async () => {
|
|||
const symKey = await generateKeyFromPassword(chatId)
|
||||
|
||||
expect(bytesToHex(symKey)).toEqual(
|
||||
'76ff5bf0a74a8e724367c7fc003f066d477641f468768a8da2817addf5c2ce76'
|
||||
'76ff5bf0a74a8e724367c7fc003f066d477641f468768a8da2817addf5c2ce76',
|
||||
)
|
||||
})
|
||||
|
|
|
@ -8,13 +8,13 @@ const AES_KEY_LENGTH = 32 // bytes
|
|||
* status-go: https://github.com/status-im/status-go/blob/a471fed6a64e01a1aba8d925377fba045a5aa9f9/wakuv2/waku.go#L713
|
||||
*/
|
||||
export async function generateKeyFromPassword(
|
||||
password: string
|
||||
password: string,
|
||||
): Promise<Uint8Array> {
|
||||
return await pbkdf2(
|
||||
utf8ToBytes(password),
|
||||
utf8ToBytes(''),
|
||||
65356,
|
||||
AES_KEY_LENGTH,
|
||||
'sha256'
|
||||
'sha256',
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ const MAX_OFFSET = BigInt(120 * 1000)
|
|||
|
||||
export function isClockValid(
|
||||
messageClock: bigint,
|
||||
messageTimestamp: Date
|
||||
messageTimestamp: Date,
|
||||
): boolean {
|
||||
if (messageClock <= 0) {
|
||||
return false
|
||||
|
|
|
@ -3,7 +3,7 @@ import { bytesToHex, concatBytes } from 'ethereum-cryptography/utils'
|
|||
|
||||
export function payloadToId(
|
||||
payload: Uint8Array,
|
||||
publicKey: Uint8Array
|
||||
publicKey: Uint8Array,
|
||||
): string {
|
||||
const hash = keccak256(concatBytes(publicKey, payload)) // order matters
|
||||
const hex = bytesToHex(hash)
|
||||
|
|
|
@ -8,8 +8,8 @@ import {
|
|||
test('should return color hash from public key', () => {
|
||||
expect(
|
||||
publicKeyToColorHash(
|
||||
'0x04e25da6994ea2dc4ac70727e07eca153ae92bf7609db7befb7ebdceaad348f4fc55bbe90abf9501176301db5aa103fc0eb3bc3750272a26c424a10887db2a7ea8'
|
||||
)
|
||||
'0x04e25da6994ea2dc4ac70727e07eca153ae92bf7609db7befb7ebdceaad348f4fc55bbe90abf9501176301db5aa103fc0eb3bc3750272a26c424a10887db2a7ea8',
|
||||
),
|
||||
).toEqual([
|
||||
[3, 30],
|
||||
[2, 10],
|
||||
|
@ -30,13 +30,13 @@ test('should throw for invalid public keys', () => {
|
|||
expect(() => publicKeyToColorHash('0x01')).toThrow()
|
||||
expect(() =>
|
||||
publicKeyToColorHash(
|
||||
'0x01e25da6994ea2dc4ac70727e07eca153ae92bf7609db7befb7ebdceaad348f4fc55bbe90abf9501176301db5aa103fc0eb3bc3750272a26c424a10887db2a7ea8'
|
||||
)
|
||||
'0x01e25da6994ea2dc4ac70727e07eca153ae92bf7609db7befb7ebdceaad348f4fc55bbe90abf9501176301db5aa103fc0eb3bc3750272a26c424a10887db2a7ea8',
|
||||
),
|
||||
).toThrow()
|
||||
expect(() =>
|
||||
publicKeyToColorHash(
|
||||
'0x04425da6994ea2dc4ac70727e07eca153ae92bf7609db7befb7ebdceaad348f4fc55bbe90abf9501176301db5aa103fc0eb3bc3750272a26c424a10887db2a7ea8'
|
||||
)
|
||||
'0x04425da6994ea2dc4ac70727e07eca153ae92bf7609db7befb7ebdceaad348f4fc55bbe90abf9501176301db5aa103fc0eb3bc3750272a26c424a10887db2a7ea8',
|
||||
),
|
||||
).toThrow()
|
||||
})
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ export function publicKeyToColorHash(publicKey: string): ColorHash {
|
|||
const colorHash = hexToColorHash(
|
||||
colorHashHex,
|
||||
COLOR_HASH_COLORS_COUNT,
|
||||
COLOR_HASH_SEGMENT_MAX_LENGTH
|
||||
COLOR_HASH_SEGMENT_MAX_LENGTH,
|
||||
)
|
||||
|
||||
return colorHash
|
||||
|
@ -26,11 +26,11 @@ export function publicKeyToColorHash(publicKey: string): ColorHash {
|
|||
export function hexToColorHash(
|
||||
hex: string,
|
||||
colorsCount: number,
|
||||
segmentLength: number
|
||||
segmentLength: number,
|
||||
): ColorHash {
|
||||
const colorIndices = numberToIndices(
|
||||
BigInt(`0x${hex}`),
|
||||
BigInt(colorsCount * segmentLength)
|
||||
BigInt(colorsCount * segmentLength),
|
||||
)
|
||||
const colorHash = colorIndicesToColorHash(colorIndices, colorsCount)
|
||||
|
||||
|
@ -57,7 +57,7 @@ export function numberToIndices(number: bigint, base: bigint): bigint[] {
|
|||
|
||||
function colorIndicesToColorHash(
|
||||
colorIndices: bigint[],
|
||||
colorsCount: number
|
||||
colorsCount: number,
|
||||
): ColorHash {
|
||||
const colorHash: ColorHash = []
|
||||
let previousColorIndex: number | undefined = undefined
|
||||
|
|
|
@ -5,23 +5,23 @@ import { publicKeyToEmojiHash } from './public-key-to-emoji-hash'
|
|||
test('should return emoji hash from public key', () => {
|
||||
expect(
|
||||
publicKeyToEmojiHash(
|
||||
'0x04e25da6994ea2dc4ac70727e07eca153ae92bf7609db7befb7ebdceaad348f4fc55bbe90abf9501176301db5aa103fc0eb3bc3750272a26c424a10887db2a7ea8'
|
||||
)
|
||||
'0x04e25da6994ea2dc4ac70727e07eca153ae92bf7609db7befb7ebdceaad348f4fc55bbe90abf9501176301db5aa103fc0eb3bc3750272a26c424a10887db2a7ea8',
|
||||
),
|
||||
).toEqual('👦🏽🦹🏻👶🏿🛁🌁🙌🏻🙇🏽♂️🙌🏾🤥🐛👩🏽🔧🔧⚙️🧒🏽')
|
||||
expect(
|
||||
publicKeyToEmojiHash(
|
||||
'0x0400000000000000000000000000000000000000000000000000000000000000014218F20AE6C646B363DB68605822FB14264CA8D2587FDD6FBC750D587E76A7EE'
|
||||
)
|
||||
'0x0400000000000000000000000000000000000000000000000000000000000000014218F20AE6C646B363DB68605822FB14264CA8D2587FDD6FBC750D587E76A7EE',
|
||||
),
|
||||
).toEqual('😀😀😀😀😀😀😀😀😀😀😀😀😀😀')
|
||||
expect(
|
||||
publicKeyToEmojiHash(
|
||||
'0x04000000000000000000000000000000000000000010000000000000000000000033600332D373318ECC2F212A30A5750D2EAC827B6A32B33D326CCF369B12B1BE'
|
||||
)
|
||||
'0x04000000000000000000000000000000000000000010000000000000000000000033600332D373318ECC2F212A30A5750D2EAC827B6A32B33D326CCF369B12B1BE',
|
||||
),
|
||||
).toEqual('😀😀😀😀😀😀😀😀😀😀😀😀😀😃')
|
||||
expect(
|
||||
publicKeyToEmojiHash(
|
||||
'0x040000000000000000000000000000000000000000200000000000000000000000353050BFE33B724E60A0C600FBA565A9B62217B1BD35BF9848F2AB847C598B30'
|
||||
)
|
||||
'0x040000000000000000000000000000000000000000200000000000000000000000353050BFE33B724E60A0C600FBA565A9B62217B1BD35BF9848F2AB847C598B30',
|
||||
),
|
||||
).toEqual('😀😀😀😀😀😀😀😀😀😀😀😀😀😄')
|
||||
})
|
||||
|
||||
|
@ -30,12 +30,12 @@ test('should throw for invalid public keys', () => {
|
|||
expect(() => publicKeyToEmojiHash('0x01')).toThrow()
|
||||
expect(() =>
|
||||
publicKeyToEmojiHash(
|
||||
'0x01e25da6994ea2dc4ac70727e07eca153ae92bf7609db7befb7ebdceaad348f4fc55bbe90abf9501176301db5aa103fc0eb3bc3750272a26c424a10887db2a7ea8'
|
||||
)
|
||||
'0x01e25da6994ea2dc4ac70727e07eca153ae92bf7609db7befb7ebdceaad348f4fc55bbe90abf9501176301db5aa103fc0eb3bc3750272a26c424a10887db2a7ea8',
|
||||
),
|
||||
).toThrow()
|
||||
expect(() =>
|
||||
publicKeyToEmojiHash(
|
||||
'0x04425da6994ea2dc4ac70727e07eca153ae92bf7609db7befb7ebdceaad348f4fc55bbe90abf9501176301db5aa103fc0eb3bc3750272a26c424a10887db2a7ea8'
|
||||
)
|
||||
'0x04425da6994ea2dc4ac70727e07eca153ae92bf7609db7befb7ebdceaad348f4fc55bbe90abf9501176301db5aa103fc0eb3bc3750272a26c424a10887db2a7ea8',
|
||||
),
|
||||
).toThrow()
|
||||
})
|
||||
|
|
|
@ -19,7 +19,7 @@ export function publicKeyToEmojiHash(publicKey: string): string {
|
|||
const emojiHash = hexToEmojiHash(
|
||||
emojiHashHex,
|
||||
MIN_EMOJI_HASH_EMOJIS_COUNT,
|
||||
EMOJI_HASH_LENGTH
|
||||
EMOJI_HASH_LENGTH,
|
||||
)
|
||||
|
||||
return emojiHash
|
||||
|
@ -28,7 +28,7 @@ export function publicKeyToEmojiHash(publicKey: string): string {
|
|||
export function hexToEmojiHash(
|
||||
hex: string,
|
||||
emojisCount: number,
|
||||
hashLength: number
|
||||
hashLength: number,
|
||||
): string {
|
||||
const emojiIndices = numberToIndices(BigInt(`0x${hex}`), BigInt(emojisCount))
|
||||
const emojiHash = emojiIndicesToEmojiHash(emojiIndices, hashLength)
|
||||
|
|
|
@ -5,7 +5,7 @@ import { publicKeyToETHAddress } from './public-key-to-eth-address'
|
|||
test('should return ETH address from public key', () => {
|
||||
expect(
|
||||
publicKeyToETHAddress(
|
||||
'0x02bcbe39785b55a22383f82ac631ea7500e204627369c4ea01d9296af0ea573f57'
|
||||
)
|
||||
'0x02bcbe39785b55a22383f82ac631ea7500e204627369c4ea01d9296af0ea573f57',
|
||||
),
|
||||
).toEqual('0x0A1ec0002dDB927B03049F1aD8D589aBEA4Ba4b3')
|
||||
})
|
||||
|
|
|
@ -18,7 +18,7 @@ test('should recover public key', async () => {
|
|||
const signature = await account.sign(payload)
|
||||
|
||||
expect(bytesToHex(recoverPublicKey(signature, payload))).toEqual(
|
||||
account.publicKey
|
||||
account.publicKey,
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -56,7 +56,7 @@ test('should recover public key from fixture', async () => {
|
|||
|
||||
const result = recoverPublicKey(
|
||||
metadataFixture.signature,
|
||||
metadataFixture.payload
|
||||
metadataFixture.payload,
|
||||
)
|
||||
|
||||
expect(result).toEqual(publicKeySnapshot)
|
||||
|
@ -80,6 +80,6 @@ test('should throw error when signature length is not 65 bytes', async () => {
|
|||
])
|
||||
|
||||
expect(() =>
|
||||
recoverPublicKey(signature, payload)
|
||||
recoverPublicKey(signature, payload),
|
||||
).toThrowErrorMatchingInlineSnapshot(`"Signature must be 65 bytes long"`)
|
||||
})
|
||||
|
|
|
@ -8,7 +8,7 @@ import { recoverPublicKey as secpRecoverPublicKey } from 'ethereum-cryptography/
|
|||
*/
|
||||
export function recoverPublicKey(
|
||||
sig: Uint8Array,
|
||||
payload: Uint8Array
|
||||
payload: Uint8Array,
|
||||
): Uint8Array {
|
||||
if (sig.length !== 65) {
|
||||
throw new Error('Signature must be 65 bytes long')
|
||||
|
|
|
@ -5,35 +5,35 @@ import { serializePublicKey } from './serialize-public-key'
|
|||
test('should serialize compressed public key to base58btc encoding', () => {
|
||||
expect(
|
||||
serializePublicKey(
|
||||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133'
|
||||
)
|
||||
'0x029f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133',
|
||||
),
|
||||
).toEqual('zQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU')
|
||||
})
|
||||
|
||||
test('should serialize uncompressed public key to base58btc encoding', () => {
|
||||
expect(
|
||||
serializePublicKey(
|
||||
'0x049f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb454295513305b23fcf11d005ee622144fc402b713a8928f80d705781e2e78d701c6e01bfc4'
|
||||
)
|
||||
'0x049f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb454295513305b23fcf11d005ee622144fc402b713a8928f80d705781e2e78d701c6e01bfc4',
|
||||
),
|
||||
).toEqual('zQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU')
|
||||
})
|
||||
|
||||
test('should return the public key if already serialized to base58btc encoding', () => {
|
||||
expect(
|
||||
serializePublicKey('zQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU')
|
||||
serializePublicKey('zQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU'),
|
||||
).toEqual('zQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU')
|
||||
})
|
||||
|
||||
test('should throw when serializing unsupported multibase encoding', () => {
|
||||
expect(() =>
|
||||
serializePublicKey('ZQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU')
|
||||
serializePublicKey('ZQ3shY7r4cAdg4eUF5dfcuCqCFzWmdjHW4SX5hspM9ucAarfU'),
|
||||
).toThrowError()
|
||||
})
|
||||
|
||||
test('should throw when serializing invalid public key', () => {
|
||||
expect(() =>
|
||||
serializePublicKey(
|
||||
'0x019f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133'
|
||||
)
|
||||
'0x019f196bbfef4fa6a5eb81dd802133a63498325445ca1af1d154b1bb4542955133',
|
||||
),
|
||||
).toThrowError()
|
||||
})
|
||||
|
|
|
@ -7,10 +7,10 @@ import { deserializePublicKey } from './deserialize-public-key'
|
|||
* @see https://specs.status.im/spec/2#public-key-serialization for specification
|
||||
*/
|
||||
export function serializePublicKey(
|
||||
publicKey: string // uncompressed, compressed, or compressed & encoded
|
||||
publicKey: string, // uncompressed, compressed, or compressed & encoded
|
||||
): string {
|
||||
const hexadecimalPublicKey = hexToBytes(
|
||||
deserializePublicKey(publicKey).replace(/^0[xX]/, '')
|
||||
deserializePublicKey(publicKey).replace(/^0[xX]/, ''),
|
||||
) // validated and compressed
|
||||
|
||||
return base58btc.encode(new Uint8Array([231, 1, ...hexadecimalPublicKey]))
|
||||
|
|
|
@ -13,7 +13,7 @@ import { recoverPublicKey } from './recover-public-key'
|
|||
*/
|
||||
export async function signData(
|
||||
data: Uint8Array | string,
|
||||
privateKey: Uint8Array | string
|
||||
privateKey: Uint8Array | string,
|
||||
): Promise<Uint8Array> {
|
||||
const bytes = ensureBytes(data)
|
||||
const hash = keccak256(bytes)
|
||||
|
@ -29,7 +29,7 @@ export async function signData(
|
|||
export function verifySignedData(
|
||||
signature: Uint8Array,
|
||||
data: Uint8Array | string,
|
||||
publicKey?: string
|
||||
publicKey?: string,
|
||||
): boolean {
|
||||
const bytes = ensureBytes(data)
|
||||
const hash = keccak256(bytes)
|
||||
|
|
2216
pnpm-lock.yaml
2216
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -9,6 +9,9 @@
|
|||
"dependsOn": ["^build"],
|
||||
"outputs": ["dist/**", "storybook-static/**"]
|
||||
},
|
||||
"connector#build": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"dev": {
|
||||
"cache": false
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue