* Fix #834: Do not remove trailing slash from Safe app url * Use correct url in id * prevent adding existing App * Limiting App name length persisted in origin field Co-authored-by: Richard Meissner <richard@gnosis.io> Co-authored-by: nicosampler <nf.dominguez.87@gmail.com>
This commit is contained in:
parent
a98652abe4
commit
051080c239
|
@ -13,6 +13,7 @@ import GnoForm from '~/components/forms/GnoForm'
|
||||||
import { required } from '~/components/forms/validator'
|
import { required } from '~/components/forms/validator'
|
||||||
import Img from '~/components/layout/Img'
|
import Img from '~/components/layout/Img'
|
||||||
import appsIconSvg from '~/routes/safe/components/Transactions/TxsTable/TxType/assets/appsIcon.svg'
|
import appsIconSvg from '~/routes/safe/components/Transactions/TxsTable/TxType/assets/appsIcon.svg'
|
||||||
|
import { isValid as isURLValid } from '~/utils/url'
|
||||||
|
|
||||||
const FORM_ID = 'add-apps-form'
|
const FORM_ID = 'add-apps-form'
|
||||||
|
|
||||||
|
@ -51,9 +52,7 @@ type Props = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const urlValidator = (value: string) => {
|
const urlValidator = (value: string) => {
|
||||||
return /(?:^|[ \t])((https?:\/\/)?(?:localhost|[\w-]+(?:\.[\w-]+)+)(:\d+)?(\/\S*)?)/gm.test(value)
|
return isURLValid(value) ? undefined : 'Please, provide a valid url'
|
||||||
? undefined
|
|
||||||
: 'Please, provide a valid url'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const composeValidatorsApps = (...validators: Function[]): FieldValidator => (value: Field, values, meta) => {
|
const composeValidatorsApps = (...validators: Function[]): FieldValidator => (value: Field, values, meta) => {
|
||||||
|
@ -92,7 +91,15 @@ const ManageApps = ({ appList, onAppAdded, onAppToggle }: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const uniqueAppValidator = (value) => {
|
const uniqueAppValidator = (value) => {
|
||||||
const exists = appList.find((a) => a.url === value.trim())
|
const exists = appList.find((a) => {
|
||||||
|
try {
|
||||||
|
const currentUrl = new URL(a.url)
|
||||||
|
const newUrl = new URL(value)
|
||||||
|
return currentUrl.href === newUrl.href
|
||||||
|
} catch (error) {
|
||||||
|
return 'There was a problem trying to validate the URL existence.'
|
||||||
|
}
|
||||||
|
})
|
||||||
return exists ? 'This app is already registered.' : undefined
|
return exists ? 'This app is already registered.' : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,40 +29,45 @@ export const getAppInfoFromUrl = async (appUrl: string) => {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
let cleanedUpAppUrl = appUrl.trim()
|
res.url = appUrl.trim()
|
||||||
if (cleanedUpAppUrl.substr(-1) === '/') {
|
let noTrailingSlashUrl = res.url
|
||||||
cleanedUpAppUrl = cleanedUpAppUrl.substr(0, cleanedUpAppUrl.length - 1)
|
if (noTrailingSlashUrl.substr(-1) === '/') {
|
||||||
res.url = cleanedUpAppUrl
|
noTrailingSlashUrl = noTrailingSlashUrl.substr(0, noTrailingSlashUrl.length - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const appInfo = await axios.get(`${cleanedUpAppUrl}/manifest.json`)
|
const appInfo = await axios.get(`${noTrailingSlashUrl}/manifest.json`)
|
||||||
|
|
||||||
// verify imported app fulfil safe requirements
|
// verify imported app fulfil safe requirements
|
||||||
if (!appInfo || !appInfo.data || !appInfo.data.name || !appInfo.data.description) {
|
if (!appInfo || !appInfo.data || !appInfo.data.name || !appInfo.data.description) {
|
||||||
throw Error('The app does not fulfil the structure required.')
|
throw Error('The app does not fulfil the structure required.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the DB origin field has a limit of 100 characters
|
||||||
|
const originFieldSize = 100
|
||||||
|
const jsonDataLength = 20
|
||||||
|
const remainingSpace = originFieldSize - res.url.length - jsonDataLength
|
||||||
|
|
||||||
res = {
|
res = {
|
||||||
...res,
|
...res,
|
||||||
...appInfo.data,
|
...appInfo.data,
|
||||||
id: JSON.stringify({ url: cleanedUpAppUrl, name: appInfo.data.name }),
|
id: JSON.stringify({ url: res.url, name: appInfo.data.name.substring(0, remainingSpace) }),
|
||||||
error: false,
|
error: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appInfo.data.iconPath) {
|
if (appInfo.data.iconPath) {
|
||||||
try {
|
try {
|
||||||
const iconInfo = await axios.get(`${cleanedUpAppUrl}/${appInfo.data.iconPath}`)
|
const iconInfo = await axios.get(`${noTrailingSlashUrl}/${appInfo.data.iconPath}`, { timeout: 1000 * 10 })
|
||||||
if (/image\/\w/gm.test(iconInfo.headers['content-type'])) {
|
if (/image\/\w/gm.test(iconInfo.headers['content-type'])) {
|
||||||
res.iconUrl = `${cleanedUpAppUrl}/${appInfo.data.iconPath}`
|
res.iconUrl = `${noTrailingSlashUrl}/${appInfo.data.iconPath}`
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`It was not possible to fetch icon from app ${cleanedUpAppUrl}`)
|
console.error(`It was not possible to fetch icon from app ${res.url}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`It was not possible to fetch app from ${cleanedUpAppUrl}: ${error.message}`)
|
console.error(`It was not possible to fetch app from ${res.url}: ${error.message}`)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue