Fix #834: Do not remove trailing slash from Safe app url (#839)

* 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:
Richard Meissner 2020-05-07 13:47:51 +02:00 committed by GitHub
parent a98652abe4
commit 051080c239
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 15 deletions

View File

@ -13,6 +13,7 @@ import GnoForm from '~/components/forms/GnoForm'
import { required } from '~/components/forms/validator'
import Img from '~/components/layout/Img'
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'
@ -51,9 +52,7 @@ type Props = {
}
const urlValidator = (value: string) => {
return /(?:^|[ \t])((https?:\/\/)?(?:localhost|[\w-]+(?:\.[\w-]+)+)(:\d+)?(\/\S*)?)/gm.test(value)
? undefined
: 'Please, provide a valid url'
return isURLValid(value) ? undefined : 'Please, provide a valid url'
}
const composeValidatorsApps = (...validators: Function[]): FieldValidator => (value: Field, values, meta) => {
@ -92,7 +91,15 @@ const ManageApps = ({ appList, onAppAdded, onAppToggle }: Props) => {
}
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
}

View File

@ -29,40 +29,45 @@ export const getAppInfoFromUrl = async (appUrl: string) => {
return res
}
let cleanedUpAppUrl = appUrl.trim()
if (cleanedUpAppUrl.substr(-1) === '/') {
cleanedUpAppUrl = cleanedUpAppUrl.substr(0, cleanedUpAppUrl.length - 1)
res.url = cleanedUpAppUrl
res.url = appUrl.trim()
let noTrailingSlashUrl = res.url
if (noTrailingSlashUrl.substr(-1) === '/') {
noTrailingSlashUrl = noTrailingSlashUrl.substr(0, noTrailingSlashUrl.length - 1)
}
try {
const appInfo = await axios.get(`${cleanedUpAppUrl}/manifest.json`)
const appInfo = await axios.get(`${noTrailingSlashUrl}/manifest.json`)
// verify imported app fulfil safe requirements
if (!appInfo || !appInfo.data || !appInfo.data.name || !appInfo.data.description) {
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,
...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,
}
if (appInfo.data.iconPath) {
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'])) {
res.iconUrl = `${cleanedUpAppUrl}/${appInfo.data.iconPath}`
res.iconUrl = `${noTrailingSlashUrl}/${appInfo.data.iconPath}`
}
} 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
} 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
}
}