Good day, are there anyway to Protect my JSON file/data on my Documents Directory?
Thanks in advance
Good day, are there anyway to Protect my JSON file/data on my Documents Directory?
Thanks in advance
The only real “safe” files are ones on a server. If it’s on the phone nothing prevents them from opening them or deleting them. And if it’s loaded by the app the data is viewable.
If your goal is security you can iterate the loop and encrypt the fields/data. The client app will need to decode it when loaded. That will at least make it harder. The data would still be viewable in the app memory space.
If your goal is simply preserving the file. All you can do is give it a unique name like MYAPP_DATA_DO_NOT_DELETE.
Even IF there was a method to protect a file. You have to keep in mind while developing that a rooted/jailbroken device gives the user root access. Which means anything they want to do can be done with the highest authority. There’s no protecting anything in that case.
I use this
local M = {} local json = require("json") local \_defaultLocation = system.DocumentsDirectory local \_realDefaultLocation = \_defaultLocation local \_validLocations = { [system.DocumentsDirectory] = true, [system.CachesDirectory] = true, [system.TemporaryDirectory] = true } local enc1 = {8623, 4234, 342, 61, 12}; -- change these numbers local function convert( chars, dist, inv ) return string.char( ( string.byte( chars ) - 32 + ( inv and -dist or dist ) ) % 95 + 32 ) end local crypt = function (str,k,inv) local enc= ""; for i=1,#str do if(#str-k[5] \>= i or not inv)then for inc=0,3 do if(i%4 == inc)then enc = enc .. convert(string.sub(str,i,i),k[inc+1],inv); break; end end end end if(not inv)then for i=1,k[5] do enc = enc .. string.char(math.random(32,126)); end end return enc; end function M.saveTable(t, filename, location) if location and (not \_validLocations[location]) then error("Attempted to save a table to an invalid location", 2) elseif not location then location = \_defaultLocation end local path = system.pathForFile( filename, location) local file = io.open(path, "w") if file then local contents = json.encode(t) local tempString = crypt(contents,enc1,false) file:write( tempString ) io.close( file ) return true else return false end end function M.loadTable(filename, location) if location and (not \_validLocations[location]) then error("Attempted to load a table from an invalid location", 2) elseif not location then location = \_defaultLocation end local path = system.pathForFile( filename, location) local contents = "" local myTable = {} local file = io.open( path, "r" ) if file then -- read all contents of file into a string local contents = file:read( "\*a" ) local tempString = crypt(contents,enc1,true) myTable = json.decode(tempString); io.close( file ) return myTable end return nil end function M.changeDefault(location) if location and (not location) then error("Attempted to change the default location to an invalid location", 2) elseif not location then location = \_realDefaultLocation end \_defaultLocation = location return true end function M.print\_r ( t ) local print\_r\_cache={} local function sub\_print\_r(t,indent) if (print\_r\_cache[tostring(t)]) then print(indent.."\*"..tostring(t)) else print\_r\_cache[tostring(t)]=true if (type(t)=="table") then for pos,val in pairs(t) do if (type(val)=="table") then print(indent.."["..pos.."] =\> "..tostring(t).." {") sub\_print\_r(val,indent..string.rep(" ",string.len(pos)+8)) print(indent..string.rep(" ",string.len(pos)+6).."}") elseif (type(val)=="string") then print(indent.."["..pos..'] =\> "'..val..'"') else print(indent.."["..pos.."] =\> "..tostring(val)) end end else print(indent..tostring(t)) end end end if (type(t)=="table") then print(tostring(t).." {") sub\_print\_r(t," ") print("}") else sub\_print\_r(t," ") end print() end M.printTable = M.print\_r return M
This is based on robs load save module (https://github.com/robmiracle/Simple-Table-Load-Save-Functions-for-Corona-SDK)
The user can still delete this file or edit it, but won’t be able to read or understand it
As long as it can’t be read it’s okay, Thanks for the answers 
Nice implementation 
scottrules44: very nice
It would be even more sweet if the crypt function implemented the scrypt(*)
encryption algorithm. That way security sensitive apps could require a user
to provide a password during the application startup.
This would make a brute force attack on the encrypted json file a bit
harder.
* = https://en.wikipedia.org/wiki/Scrypt
I have on my TODO to implement scrypt in lua. Have not seen any lua scrypt
implementation out there.
Cheers
/Jocke
The only real “safe” files are ones on a server. If it’s on the phone nothing prevents them from opening them or deleting them. And if it’s loaded by the app the data is viewable.
If your goal is security you can iterate the loop and encrypt the fields/data. The client app will need to decode it when loaded. That will at least make it harder. The data would still be viewable in the app memory space.
If your goal is simply preserving the file. All you can do is give it a unique name like MYAPP_DATA_DO_NOT_DELETE.
Even IF there was a method to protect a file. You have to keep in mind while developing that a rooted/jailbroken device gives the user root access. Which means anything they want to do can be done with the highest authority. There’s no protecting anything in that case.
I use this
local M = {} local json = require("json") local \_defaultLocation = system.DocumentsDirectory local \_realDefaultLocation = \_defaultLocation local \_validLocations = { [system.DocumentsDirectory] = true, [system.CachesDirectory] = true, [system.TemporaryDirectory] = true } local enc1 = {8623, 4234, 342, 61, 12}; -- change these numbers local function convert( chars, dist, inv ) return string.char( ( string.byte( chars ) - 32 + ( inv and -dist or dist ) ) % 95 + 32 ) end local crypt = function (str,k,inv) local enc= ""; for i=1,#str do if(#str-k[5] \>= i or not inv)then for inc=0,3 do if(i%4 == inc)then enc = enc .. convert(string.sub(str,i,i),k[inc+1],inv); break; end end end end if(not inv)then for i=1,k[5] do enc = enc .. string.char(math.random(32,126)); end end return enc; end function M.saveTable(t, filename, location) if location and (not \_validLocations[location]) then error("Attempted to save a table to an invalid location", 2) elseif not location then location = \_defaultLocation end local path = system.pathForFile( filename, location) local file = io.open(path, "w") if file then local contents = json.encode(t) local tempString = crypt(contents,enc1,false) file:write( tempString ) io.close( file ) return true else return false end end function M.loadTable(filename, location) if location and (not \_validLocations[location]) then error("Attempted to load a table from an invalid location", 2) elseif not location then location = \_defaultLocation end local path = system.pathForFile( filename, location) local contents = "" local myTable = {} local file = io.open( path, "r" ) if file then -- read all contents of file into a string local contents = file:read( "\*a" ) local tempString = crypt(contents,enc1,true) myTable = json.decode(tempString); io.close( file ) return myTable end return nil end function M.changeDefault(location) if location and (not location) then error("Attempted to change the default location to an invalid location", 2) elseif not location then location = \_realDefaultLocation end \_defaultLocation = location return true end function M.print\_r ( t ) local print\_r\_cache={} local function sub\_print\_r(t,indent) if (print\_r\_cache[tostring(t)]) then print(indent.."\*"..tostring(t)) else print\_r\_cache[tostring(t)]=true if (type(t)=="table") then for pos,val in pairs(t) do if (type(val)=="table") then print(indent.."["..pos.."] =\> "..tostring(t).." {") sub\_print\_r(val,indent..string.rep(" ",string.len(pos)+8)) print(indent..string.rep(" ",string.len(pos)+6).."}") elseif (type(val)=="string") then print(indent.."["..pos..'] =\> "'..val..'"') else print(indent.."["..pos.."] =\> "..tostring(val)) end end else print(indent..tostring(t)) end end end if (type(t)=="table") then print(tostring(t).." {") sub\_print\_r(t," ") print("}") else sub\_print\_r(t," ") end print() end M.printTable = M.print\_r return M
This is based on robs load save module (https://github.com/robmiracle/Simple-Table-Load-Save-Functions-for-Corona-SDK)
The user can still delete this file or edit it, but won’t be able to read or understand it
As long as it can’t be read it’s okay, Thanks for the answers 
Nice implementation 
scottrules44: very nice
It would be even more sweet if the crypt function implemented the scrypt(*)
encryption algorithm. That way security sensitive apps could require a user
to provide a password during the application startup.
This would make a brute force attack on the encrypted json file a bit
harder.
* = https://en.wikipedia.org/wiki/Scrypt
I have on my TODO to implement scrypt in lua. Have not seen any lua scrypt
implementation out there.
Cheers
/Jocke