Starlight
Starlight

Reputation: 27

Cloudinary Signed Uploads and Unsigned Uploads implementations in Kotlin?

Thanks to this Cloudinary post and Medium post, I was able to implement unsigned upload:

package com.example.calculatorapp

import android.app.Activity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.ImageView
import android.widget.Toast
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.cloudinary.android.MediaManager
import com.cloudinary.android.callback.ErrorInfo
import com.cloudinary.android.callback.UploadCallback
import com.github.dhaval2404.imagepicker.ImagePicker
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase


class MainActivity : AppCompatActivity() {
    // Access a Cloud Firestore instance from your Activity
    val db = Firebase.firestore
    var config: HashMap<String, String> = HashMap()

    private lateinit var imageV: ImageView;

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        imageV = findViewById<ImageView>(R.id.imageV)
        config.put("cloud_name", BuildConfig.CLOUD_NAME);
        MediaManager.init(this, config)

        ImagePicker.with(this)
            .compress(1024)         //Final image size will be less than 1 MB(Optional)
            .maxResultSize(1080, 1080)  //Final image resolution will be less than 1080 x 1080(Optional)
            .createIntent { intent ->
                startForProfileImageResult.launch(intent)
            }

//        val intent = Intent(this, MainActivity::class.java)
//        resultLauncher.launch(intent)
    }

    fun onDigit(view: View) {
        Toast.makeText(this, "clicked", Toast.LENGTH_LONG).show()
    }

    private val startForProfileImageResult =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
            Log.d("test", "HEYYYY")

            val resultCode = result.resultCode
            val data = result.data

            if (resultCode == Activity.RESULT_OK) {
                //Image Uri will not be null for RESULT_OK
                val fileUri = data?.data!!
                val filePath: String = fileUri.path!!

                imageV.setImageURI(fileUri)
                Log.d("test", filePath)
                uploadToCloudinary(filePath)
            } else if (resultCode == ImagePicker.RESULT_ERROR) {
                Toast.makeText(this, ImagePicker.getError(data), Toast.LENGTH_SHORT).show()
            } else {
                Toast.makeText(this, "Task Cancelled", Toast.LENGTH_SHORT).show()
            }
        }

    private fun uploadToCloudinary(filepath: String) {
        MediaManager.get().upload(filepath).unsigned("your_upload_preset").callback(object : UploadCallback {
            override fun onSuccess(requestId: String?, resultData: MutableMap<Any?, Any?>?) {
                Log.d("cloudinary", "Task successful")

                Toast.makeText(applicationContext, "Task successful", Toast.LENGTH_LONG).show()
            }

            override fun onProgress(requestId: String?, bytes: Long, totalBytes: Long) {
                val progress = bytes.toDouble() / totalBytes

            }

            override fun onReschedule(requestId: String?, error: ErrorInfo?) {
                Log.d("cloudinary", "Task rescheduled")

            }

            override fun onError(requestId: String?, error: ErrorInfo?) {
                Log.d("cloudinary", "Task Not successful$error")
                Toast.makeText(applicationContext, "Task Not successful$error", Toast.LENGTH_LONG)
                    .show()
                if (error != null) {
                    Log.e(
                        "t",
                        "Upload failed. Error description: ${error.description}, Code: ${error.code}"
                    )
                } else {
                    Log.e("t", "Upload failed with unknown error")
                }
            }

            override fun onStart(requestId: String?) {
                Log.d("cloudinary", "Start")

                Toast.makeText(applicationContext, "Start", Toast.LENGTH_LONG).show()
            }
        }).dispatch()
    }
}

Now, I have the following questions:

  1. Based on this post, when implementing Unsigned Uploads, to secure my Cloudinary, do I just need to conceal my upload preset when uploading my project on GitHub?
  2. Having unsigned upload approach, I have not thought of a specific use case on why I should use signed upload? Does it impose more restrictions on uploads? Could you guide me in implementing signed uploads in Kotlin?

Upvotes: 0

Views: 103

Answers (1)

Danny V
Danny V

Reputation: 151

Removing your upload preset (and cloud name) from the repo is definitely a good way to prevent upload abuse on your account.

As for signed uploads, this is for potentially costly or destructive operations, such as using an upload preset that invokes a paid add-on, or overwrites existing assets. I can't give an exact example in Kotlin, but the way you would typically do this is by signing the request, and then passing this signature to the upload call. https://cloudinary.com/documentation/generate_upload_signature_tutorial should be a good place to start.

Upvotes: 0

Related Questions