Skip to content

Commit

Permalink
Change base64 implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
emmatown committed May 8, 2024
1 parent c69d034 commit 8cf03e8
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 32 deletions.
4 changes: 2 additions & 2 deletions packages/keystatic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@
"ignore": "^5.2.4",
"iron-webcrypto": "^0.10.1",
"is-hotkey": "^0.2.0",
"js-base64": "^3.7.5",
"js-yaml": "^4.1.0",
"lib0": "^0.2.88",
"lru-cache": "^10.2.0",
Expand Down Expand Up @@ -282,6 +281,7 @@
"react-server": "./src/component-blocks/blank-for-react-server.tsx",
"default": "./src/component-blocks/cloud-image-preview.tsx"
},
"#markdoc": "./src/markdoc.js"
"#markdoc": "./src/markdoc.js",
"#base64": "./src/base64.ts"
}
}
6 changes: 3 additions & 3 deletions packages/keystatic/src/app/updating.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { useContext, useState } from 'react';
import { ComponentSchema, fields } from '../form/api';
import { dump } from 'js-yaml';
import { useMutation } from 'urql';
import { fromUint8Array } from 'js-base64';
import {
BranchInfoContext,
fetchGitHubTreeData,
Expand All @@ -29,6 +28,7 @@ import { AppSlugContext } from './onboarding/install-app';
import { createUrqlClient } from './provider';
import { serializeProps } from '../form/serialize-props';
import { scopeEntriesWithPathPrefix } from './shell/path-prefix';
import { base64UrlEncode } from '#base64';

const textEncoder = new TextEncoder();

Expand Down Expand Up @@ -217,7 +217,7 @@ export function useUpsertItem(args: {
fileChanges: {
additions: additions.map(addition => ({
...addition,
contents: fromUint8Array(addition.contents),
contents: base64UrlEncode(addition.contents),
})),
deletions,
},
Expand Down Expand Up @@ -298,7 +298,7 @@ export function useUpsertItem(args: {
body: JSON.stringify({
additions: additions.map(addition => ({
...addition,
contents: fromUint8Array(addition.contents),
contents: base64UrlEncode(addition.contents),
})),
deletions,
}),
Expand Down
17 changes: 6 additions & 11 deletions packages/keystatic/src/app/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fromUint8Array } from 'js-base64';
import { base64UrlEncode } from '#base64';
import { isDefined } from 'emery';

import { Config, GitHubConfig, LocalConfig } from '../config';
Expand Down Expand Up @@ -195,20 +195,15 @@ export async function redirectToCloudAuth(from: string, config: Config) {
if (!config.cloud?.project) {
throw new Error('Not a cloud config');
}
const code_verifier = fromUint8Array(
crypto.getRandomValues(new Uint8Array(32)),
true
const code_verifier = base64UrlEncode(
crypto.getRandomValues(new Uint8Array(32))
);
const code_challenge = fromUint8Array(
const code_challenge = base64UrlEncode(
new Uint8Array(
await crypto.subtle.digest('SHA-256', textEncoder.encode(code_verifier))
),
true
);
const state = fromUint8Array(
crypto.getRandomValues(new Uint8Array(32)),
true
)
);
const state = base64UrlEncode(crypto.getRandomValues(new Uint8Array(32)));
localStorage.setItem(
'keystatic-cloud-state',
JSON.stringify({ state, from, code_verifier })
Expand Down
17 changes: 17 additions & 0 deletions packages/keystatic/src/base64.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export function base64UrlDecode(base64: string) {
const binString = atob(base64.replace(/-/g, '+').replace(/_/g, '/'));
return Uint8Array.from(
binString as Iterable<number>,
m => (m as unknown as string).codePointAt(0)!
);
}

export function base64UrlEncode(bytes: Uint8Array) {
const binString = Array.from(bytes, byte => String.fromCodePoint(byte)).join(
''
);
return btoa(binString)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { isValidURL } from '../isValidURL';
import { insertNodesButReplaceIfSelectionIsAtEmptyParagraphOrHeading } from '../ui-utils';
import { deserializeHTML } from './html';
import { deserializeMarkdown } from './markdown';
import { fromUint8Array, toUint8Array } from 'js-base64';
import { base64UrlEncode, base64UrlDecode } from '#base64';
import { isBlock } from '../editor';

const urlPattern = /https?:\/\//;
Expand Down Expand Up @@ -133,7 +133,7 @@ function setFragmentData(e: Editor, data: DataTransfer) {
const string = JSON.stringify(fragment, (key, val) => {
if (val instanceof Uint8Array) {
return {
[bytesName]: fromUint8Array(val),
[bytesName]: base64UrlEncode(val),
};
}
return val;
Expand Down Expand Up @@ -184,7 +184,7 @@ export function withPasting(editor: Editor): Editor {
val !== null &&
bytesName in val &&
typeof val[bytesName] === 'string'
? toUint8Array(val[bytesName])
? base64UrlDecode(val[bytesName])
: val
) as Node[];
editor.insertFragment(parsed);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
toSerialized,
useDeserializedValue,
} from './props-serialization';
import { fromUint8Array, toUint8Array } from 'js-base64';
import { base64UrlEncode, base64UrlDecode } from '#base64';

function serializeProps(props: {
value: unknown;
Expand All @@ -35,7 +35,7 @@ function serializeProps(props: {
extraFiles: props.extraFiles.map(x => ({
path: x.path,
parent: x.parent,
contents: fromUint8Array(x.contents),
contents: base64UrlEncode(x.contents),
})),
});
}
Expand All @@ -54,7 +54,7 @@ function deserializeProps(
extraFiles: parsed.extraFiles.map((x: any) => ({
path: x.path,
parent: x.parent,
contents: toUint8Array(x.contents),
contents: base64UrlDecode(x.contents),
})),
},
};
Expand Down
6 changes: 3 additions & 3 deletions packages/keystatic/src/form/fields/markdoc/editor/schema.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { EditorConfig } from '../config';
import { toSerialized } from './props-serialization';
import { getInitialPropsValue } from '../../../initial-values';
import { getUploadedFileObject } from '../../image/ui';
import { fromUint8Array, toUint8Array } from 'js-base64';
import { base64UrlEncode, base64UrlDecode } from '#base64';

const blockElementSpacing = css({
marginBlock: '1em',
Expand Down Expand Up @@ -381,7 +381,7 @@ const nodeSpecs = {
node.attrs.filename.endsWith('.svg')
? 'image/svg+xml'
: 'application/octet-stream'
};base64,${fromUint8Array(node.attrs.src)}`,
};base64,${base64UrlEncode(node.attrs.src)}`,
alt: node.attrs.alt,
title: node.attrs.title,
'data-filename': node.attrs.filename,
Expand All @@ -396,7 +396,7 @@ const nodeSpecs = {
const src = node.getAttribute('src');
const filename = node.getAttribute('data-filename');
if (!src?.startsWith('data:') || !filename) return false;
const srcAsUint8Array = toUint8Array(
const srcAsUint8Array = base64UrlDecode(
src.replace(/^data:[a-z/-]+;base64,/, '')
);
return {
Expand Down
7 changes: 0 additions & 7 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8cf03e8

Please sign in to comment.