amazon-s3ihp

Issue uploading/accessing S3 uploads with IHP


I am having an issue with S3 in IHP, or the IHP plugin for it.

I'm saving files to AWS storage, I get an url back to save in the database, but nothing gets saved in S3. And no error message from IHP.

I have double checked bucket name and region, and access keys is connected to an IAM with AmazonS3FullAccess permissions.

I get 403 forbidden when trying to access signed urls.

Any ideas where things could have gone wrong?

Currently my controller looks like this as I per the docs is instructed to save the whole link, using the createTemporaryDownloadUrlFromPath won't work, so there are currently some holes in the docs.

    action CreateDriverAction = do
        let driver = newRecord @Driver
        driver
            |> buildDriver
            |> validateNewDriver
            >>= uploadToStorage #licenceBackUrl
            >>= pure . validateField #licenceFrontUrl (nonEmpty |> withCustomErrorMessage "Bilde av forsiden på førerkortet er obligatorisk")
            >>= pure . validateField #licenceBackUrl (nonEmpty |> withCustomErrorMessage "Bilde av baksiden på førerkortet er obligatorisk")
            >>= ifValid \case
                Left driver -> do
                    render NewView{..}
                Right driver -> do
                    hashed <- hashPassword (get #passwordHash driver)
                    driver <- driver |> set #passwordHash hashed |> createRecord
                    login driver
                    redirectToPath "/driver/"

Solution

  • When accessing files that are not publicly allowed, there are some extra steps to it, and

    You must access files with fileOrNothing and do some more manual steps.

    My action ended opp looking like this:

        action CreateDriverAction = do
            let driver = newRecord @Driver
            let licenceFrontFile = fileOrNothing "licenceFrontUrl"
            let licenceBackFile = fileOrNothing "licenceBackUrl"
    
            driver
                |> buildDriver
                |> set #licenceBackPath (maybe "" (cs . get #fileContent) licenceBackFile)
                |> set #licenceFrontPath (maybe "" (cs . get #fileContent) licenceBackFile)
                |> validateField #licenceFrontPath (nonEmpty |> withCustomErrorMessage "Bilde av forsiden på førerkortet er obligatorisk")
                |> validateField #licenceBackPath (nonEmpty |> withCustomErrorMessage "Bilde av baksiden på førerkortet er obligatorisk")
                |> validateNewDriver
                >>= ifValid \case
                    Left driver -> do
                        setErrorMessage "Noe gikk galt med fører-registrering. Sjekk at skjemafeltene er korrekte og send inn på nytt"
                        render NewView{..}
                    Right driver ->
                        do
                            storedLicenceFront <-
                                storeFileWithOptions
                                    (licenceFrontFile |> fromMaybe (error "No file"))
                                    ( def
                                        { directory = "drivers/licenceFront"
                                        , contentDisposition = contentDispositionAttachmentAndFileName
                                        }
                                    )
    
                            storedLicenceBack <-
                                storeFileWithOptions
                                    (licenceBackFile |> fromMaybe (error "No file"))
                                    ( def
                                        { directory = "drivers/licenceBack"
                                        , contentDisposition = contentDispositionAttachmentAndFileName
                                        }
                                    )
    
                            licenceBackSigned <- createTemporaryDownloadUrlFromPath (get #path storedLicenceBack)
                            licenceFrontSigned <- createTemporaryDownloadUrlFromPath (get #path storedLicenceFront)
                            hashed <- hashPassword (get #passwordHash driver)
                            driver <-
                                driver |> set #passwordHash hashed
                                    |> set #licenceFrontPath (get #path storedLicenceFront)
                                    |> set #licenceBackPath (get #path storedLicenceBack)
                                    |> set #licenceBackUrl (get #url licenceBackSigned)
                                    |> set #licenceFrontUrl (get #url licenceFrontSigned)
                                    |> set #licenceFrontUrlExpiresAt (get #expiredAt licenceFrontSigned)
                                    |> set #licenceBackUrlExpiresAt (get #expiredAt licenceBackSigned)
                                    |> createRecord
                            setSuccessMessage "Din førerprofil er opprettet! Vi behandler søknaden din snarest."
                            login driver
                            redirectToPath "/driver/"