Fix url problems (#1679)

* Fix Uri errors
This commit is contained in:
Rafael Saes 2022-07-12 16:58:18 -03:00 committed by GitHub
parent 68a4697c7d
commit 68ceb7f440
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 78 additions and 32 deletions

View file

@ -13,6 +13,8 @@ declare type LbryUrlObj = {
primaryBidPosition?: number,
secondaryBidPosition?: number,
startTime?: number,
queryString?: string,
pathHash?: string,
// Below are considered deprecated and should not be used due to unreliableness with claim.canonical_url
claimName?: string,

View file

@ -5,7 +5,7 @@ import { lazyImport } from 'util/lazyImport';
import { tusUnlockAndNotify, tusHandleTabUpdates } from 'util/tus';
import analytics from 'analytics';
import { setSearchUserId } from 'redux/actions/search';
import { normalizeURI } from 'util/lbryURI';
import { parseURI, buildURI } from 'util/lbryURI';
import { generateGoogleCacheUrl } from 'util/url';
import Router from 'component/router/index';
import ModalRouter from 'modal/modalRouter';
@ -187,7 +187,10 @@ function App(props: Props) {
let uri;
try {
uri = normalizeURI(path);
// here queryString and startTime are "removed" from the buildURI process
// to build only the uri itself
const { queryString, startTime, ...parsedUri } = parseURI(path);
uri = buildURI({ ...parsedUri });
} catch (e) {
const match = path.match(/[#/:]/);

View file

@ -64,7 +64,7 @@ function Page(props: Props) {
} = props;
const {
location: { pathname },
location: { pathname, hash },
} = useHistory();
const theaterMode = renderMode === 'video' || renderMode === 'audio' ? videoTheaterMode : false;
@ -73,11 +73,10 @@ function Page(props: Props) {
const isLandscapeRotated = useIsMobileLandscape();
const [sidebarOpen, setSidebarOpen] = usePersistedState('sidebar', false);
const url = pathname.slice(1).replace(/:/g, '#');
const urlPath = `lbry://${(pathname + hash).slice(1).replace(/:/g, '#')}`;
let isOnFilePage = false;
try {
const url = pathname.slice(1).replace(/:/g, '#');
const { isChannel } = parseURI(url);
const { isChannel } = parseURI(urlPath);
if (!isChannel) isOnFilePage = true;
} catch (e) {}
@ -93,7 +92,7 @@ function Page(props: Props) {
return (
<>
<Wallpaper uri={url} />
<Wallpaper uri={urlPath} />
{!noHeader && (
<Header
authHeader={authPage}

View file

@ -31,18 +31,26 @@ import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
import { selectDaemonSettings, selectClientSetting, selectHomepageData } from 'redux/selectors/settings';
import { toggleVideoTheaterMode, toggleAutoplayNext, doSetClientSetting } from 'redux/actions/settings';
import { selectUserVerifiedEmail, selectUser } from 'redux/selectors/user';
import { parseURI } from 'util/lbryURI';
import { doToast } from 'redux/actions/notifications';
const select = (state, props) => {
const { search } = props.location;
const { search, pathname, hash } = props.location;
const urlParams = new URLSearchParams(search);
const autoplay = urlParams.get('autoplay');
const uri = props.uri;
const urlPath = `lbry://${(pathname + hash).slice(1)}`;
let startTime;
try {
({ startTime } = parseURI(urlPath));
} catch (e) {}
const claim = selectClaimForUri(state, uri);
// TODO: eventually this should be received from DB and not local state (https://github.com/lbryio/lbry-desktop/issues/6796)
const position = urlParams.get('t') !== null ? urlParams.get('t') : selectContentPositionForUri(state, uri);
const position =
startTime || (urlParams.get('t') !== null ? urlParams.get('t') : selectContentPositionForUri(state, uri));
const userId = selectUser(state) && selectUser(state).id;
const internalFeature = selectUser(state) && selectUser(state).internal_feature;
const playingUri = selectPlayingUri(state);

View file

@ -137,29 +137,37 @@ export default function ShowPage(props: Props) {
useEffect(() => {
if (canonicalUrl) {
const urlPath = pathname + hash;
const fullParams =
urlPath.indexOf('?') > 0 ? urlPath.substring(urlPath.indexOf('?')) : search.length > 0 ? search : '';
const canonicalUrlPath = '/' + canonicalUrl.replace(/^lbry:\/\//, '').replace(/#/g, ':') + fullParams;
const statePos =
hash.indexOf('#state') > -1
? hash.indexOf('#state')
: hash.indexOf('&state') > -1
? hash.indexOf('&state')
: undefined;
const pageHash = statePos === undefined ? hash : hash.substring(0, statePos);
const urlPath = pathname + pageHash;
const path = urlPath.slice(1).replace(/:/g, '#');
// parseURI can parse queries and hashes when they are mixed with the uri
let queryString, pathHash;
try {
({ queryString, pathHash } = parseURI(path));
} catch (e) {}
const canonicalUrlPath = '/' + canonicalUrl.replace(/^lbry:\/\//, '').replace(/#/g, ':');
// replaceState will fail if on a different domain (like webcache.googleusercontent.com)
const hostname = isDev ? 'localhost' : DOMAIN;
if (canonicalUrlPath !== pathname && hostname === window.location.hostname && fullParams !== search) {
const urlParams = new URLSearchParams(search);
let replaceUrl = canonicalUrlPath;
if (canonicalUrlPath !== urlPath && hostname === window.location.hostname) {
const urlParams = new URLSearchParams(search || queryString);
if (urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID)) {
const listId = urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID) || '';
urlParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, listId);
replaceUrl += `?${urlParams.toString()}`;
}
history.replaceState(history.state, '', replaceUrl);
}
const windowHref = window.location.href;
const noUrlParams = search.length === 0;
if (windowHref.includes('?') && noUrlParams) {
history.replaceState(history.state, '', windowHref.substring(0, windowHref.length - 1));
if (urlParams.toString()) replaceUrl += `?${urlParams.toString()}`;
if (pathHash || (!pathHash && !queryString && pageHash)) replaceUrl += String(pathHash || pageHash);
history.replaceState(history.state, '', replaceUrl);
}
}
}, [canonicalUrl, pathname, hash, search]);

View file

@ -103,17 +103,18 @@ export function parseURI(url: string, requireProto: boolean = false): LbryUrlObj
}
// Validate and process modifier
const [primaryClaimId, primaryClaimSequence, primaryBidPosition] = parseURIModifier(
const [primaryClaimId, primaryClaimSequence, primaryBidPosition, primaryPathHash] = parseURIModifier(
primaryModSeparator,
primaryModValue
);
const [secondaryClaimId, secondaryClaimSequence, secondaryBidPosition] = parseURIModifier(
const [secondaryClaimId, secondaryClaimSequence, secondaryBidPosition, secondaryPathHash] = parseURIModifier(
secondaryModSeparator,
secondaryModValue
);
const streamName = includesChannel ? possibleStreamName : streamNameOrChannelName;
const streamClaimId = includesChannel ? secondaryClaimId : primaryClaimId;
const channelClaimId = includesChannel && primaryClaimId;
const pathHash = primaryPathHash || secondaryPathHash;
return {
isChannel,
@ -127,6 +128,7 @@ export function parseURI(url: string, requireProto: boolean = false): LbryUrlObj
...(primaryBidPosition ? { primaryBidPosition: parseInt(primaryBidPosition, 10) } : {}),
...(secondaryBidPosition ? { secondaryBidPosition: parseInt(secondaryBidPosition, 10) } : {}),
...(startTime ? { startTime: parseInt(startTime, 10) } : {}),
...(pathHash ? { pathHash } : {}),
// The values below should not be used for new uses of parseURI
// They will not work properly with canonical_urls
@ -141,6 +143,7 @@ function parseURIModifier(modSeperator: ?string, modValue: ?string) {
let claimId;
let claimSequence;
let bidPosition;
let pathHash;
if (modSeperator) {
if (!modValue) {
@ -157,8 +160,18 @@ function parseURIModifier(modSeperator: ?string, modValue: ?string) {
}
if (claimId && (claimId.length > claimIdMaxLength || !claimId.match(/^[0-9a-f]+$/))) {
const hashIndex = claimId.indexOf('#');
if (hashIndex >= 0) {
pathHash = claimId.substring(hashIndex);
claimId = claimId.substring(0, hashIndex);
// As a pre-caution to catch future odd urls coming in,
// validate the new claimId length and characters again after stripping off the pathHash
[claimId] = parseURIModifier(modSeperator, claimId);
} else {
throw new Error(__(`Invalid claim ID %claimId%.`, { claimId }));
}
}
if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]*$/)) {
throw new Error(__('Claim sequence must be a number.'));
@ -168,7 +181,7 @@ function parseURIModifier(modSeperator: ?string, modValue: ?string) {
throw new Error(__('Bid position must be a number.'));
}
return [claimId, claimSequence, bidPosition];
return [claimId, claimSequence, bidPosition, pathHash];
}
const errorHistory = [];

View file

@ -205,7 +205,7 @@ async function buildClaimOgMetadata(uri, claim, overrideOptions = {}, referrerQu
const title = overrideOptions.title || claimTitle;
const description = overrideOptions.description || claimDescription;
const cleanDescription = removeMd(description);
const claimPath = `${URL}/${claim.canonical_url.replace('lbry://', '').replace('#', ':')}`;
const claimPath = `${URL}/${claim.canonical_url.replace('lbry://', '').replace(/#/g, ':')}`;
let head = '';

View file

@ -108,17 +108,18 @@ function parseURI(url, requireProto = false) {
}
// Validate and process modifier
const [primaryClaimId, primaryClaimSequence, primaryBidPosition] = parseURIModifier(
const [primaryClaimId, primaryClaimSequence, primaryBidPosition, primaryPathHash] = parseURIModifier(
primaryModSeparator,
primaryModValue
);
const [secondaryClaimId, secondaryClaimSequence, secondaryBidPosition] = parseURIModifier(
const [secondaryClaimId, secondaryClaimSequence, secondaryBidPosition, secondaryPathHash] = parseURIModifier(
secondaryModSeparator,
secondaryModValue
);
const streamName = includesChannel ? possibleStreamName : streamNameOrChannelName;
const streamClaimId = includesChannel ? secondaryClaimId : primaryClaimId;
const channelClaimId = includesChannel && primaryClaimId;
const pathHash = primaryPathHash || secondaryPathHash;
return {
isChannel,
@ -132,6 +133,7 @@ function parseURI(url, requireProto = false) {
...(primaryBidPosition ? { primaryBidPosition: parseInt(primaryBidPosition, 10) } : {}),
...(secondaryBidPosition ? { secondaryBidPosition: parseInt(secondaryBidPosition, 10) } : {}),
...(startTime ? { startTime: parseInt(startTime, 10) } : {}),
...(pathHash ? { pathHash } : {}),
// The values below should not be used for new uses of parseURI
// They will not work properly with canonical_urls
@ -146,6 +148,7 @@ function parseURIModifier(modSeperator, modValue) {
let claimId;
let claimSequence;
let bidPosition;
let pathHash;
if (modSeperator) {
if (!modValue) {
@ -162,7 +165,17 @@ function parseURIModifier(modSeperator, modValue) {
}
if (claimId && (claimId.length > claimIdMaxLength || !claimId.match(/^[0-9a-f]+$/))) {
throw new Error(__(`Invalid claim ID ${claimId}.`, { claimId }));
const hashIndex = claimId.indexOf('#');
if (hashIndex >= 0) {
pathHash = claimId.substring(hashIndex);
claimId = claimId.substring(0, hashIndex);
// As a pre-caution to catch future odd urls coming in,
// validate the new claimId length and characters again after stripping off the pathHash
[claimId] = parseURIModifier(modSeperator, claimId);
} else {
throw new Error(__(`Invalid claim ID %claimId%.`, { claimId }));
}
}
if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]*$/)) {
@ -173,7 +186,7 @@ function parseURIModifier(modSeperator, modValue) {
throw new Error(__('Bid position must be a number.'));
}
return [claimId, claimSequence, bidPosition];
return [claimId, claimSequence, bidPosition, pathHash];
}
/**