This is my setup Firebase Storage - for storing PDF files AWS lambda - backend, using express and serverless packages. FrontEnd - Flutter mobile app and web app(using flutter)
Everything works fine when testing the code in local environment. As soon as I deploy the code to production, my app is not able to read the document at all. There is no error from backend. A response with status code 200 is returned. But somehow the
My Front end code (Flutter - Dart)
static Future<Response?> getData(String endPoint, {Function(Object)? onError}) async {
String fromURL = baseUrl + endPoint;
print(fromURL);
try {
final response = await get(Uri.parse(fromURL),
headers: {"Access-Control-Allow-Origin": "*", "Content-Type": "application/pdf"});
// if (response.body.isNotEmpty) {
// final jsonData = jsonDecode(response.body);
return response;
// }
} catch (e) {
if (onError != null) {
onError(e);
}
}
}
Future<Uint8List> _decryptPdfFile(Uint8List ecnryptedFile) async {
// File _unecnryptedPdfFile = ecnryptedFile;
final syn_pdf.PdfDocument document =
syn_pdf.PdfDocument(inputBytes: ecnryptedFile, password: 'password');
final syn_pdf.PdfSecurity security = document.security;
security.userPassword = ''; //TODO: move the passwords to env file
security.ownerPassword = '';
security.algorithm = syn_pdf.PdfEncryptionAlgorithm.aesx256Bit;
Uint8List decryptedBytes = Uint8List.fromList(document.save());
document.dispose();
return decryptedBytes;
}
Future<Uint8List> _getPdfbytes(UserFile userFile, String email) async {
final respone = await NetworkClient.getData("/api/file?fileName=${userFile.name}&email=$email");
_pdfFile = await _decryptPdfFile(respone!.bodyBytes);// Exception thrown on this line
return _pdfFile;
}
My Back-End Code
router.get("/", async (req, res) => {
const firestore = admin.firestore();
const firebaseStorage = admin.storage();
const firebaseAuth = admin.auth();
const urlParams = req.query;
try {
// console.log(req.headers);
// console.log(req);
const { email, fileName } = urlParams;
if (!email) {
return res.status(400).send({
message: "failed",
error: "unauthenticated",
});
}
const reqUser = await firebaseAuth.getUserByEmail(email);
if (!reqUser) {
return res.status(400).send({
message: "failed",
error: "unauthenticated",
});
}
let firebaseStorage = admin.storage();
const bucket = await firebaseStorage.bucket();
const file = await bucket.file(fileName);
if (!file) {
return res.status(400).send({
message: "failed",
error: "file not found",
});
}
//get download url
const urlOptions = {
action: "read",
expires: Date.now() + 1000 * 60 * 2, // 2 minutes
};
const downloadUrl = usingEmulator
? [await file.publicUrl()]
: await file.getSignedUrl({
action: "read",
expires: Date.now() + 1000 * 60 * 4,
});
// const downloadedFile = await file.download();
const respose = http.get(downloadUrl[0], (response) => {
const { statusCode } = response;
const contentType = response.headers["content-type"];
let error;
if (statusCode !== 200) {
error = new Error("Request Failed.\n" + `Status Code: ${statusCode}`);
}
if (error) {
console.error(error.message);
response.resume();
return res.status(400).send({
message: "failed",
error: error.message || error,
});
}
res.setHeader("Content-Type", contentType);
res.setHeader("Content-Disposition", `attachment; filename=${fileName}`);
response.pipe(res);
// response.end();
return res.status(200);
});
} catch (error) {
console.info(error.message);
return res.status(500).send({
message: "failed",
error: error.message || error,
});
}
});
I have checked uploaded PDF manually, and it has been uploaded fine. I tried experimenting by setting various content-type in my request headers, but that doesn't work as well. I tried debugging flutter app and an Exception is thrown at the line pointed in the code. And the Exception is
ArgumentError (Invalid argument (Invalid cross reference table.): null)
I don't get any error or exception when running this code locally using Firebase emulators and running the backend locally as well. PDF gets uploaded and also read fine.
_decryptPdfFile function is removing the password which I set during PDF upload. It's hard-coded password and has never changed.
AWS lambda URL has been added to Firebase storage CORS policy.
EDIT 01: PDF file size will never go above 1mb. Max PDF size on Firebase storage is 307 KB. EDIT02: if i trigger the get URL using browse then PDF file gets downlaoded but its blank. It asks me for password and it accepts right password but PDF file is blank. SO i thought myabe firebase storage has blank file stored as well. But when i checked firebase storage manually, it has correct pdf file.