Files

mon@razerRamon:~/tmp/DataRegister$ ll -R
.:
total 16K
drwxrwxr-x 2 mon mon 4.0K Jul 17 13:04 dataleaks/
-rwxrwxr-x 1 mon mon 1.6K Jul 17 13:02 DataRegister.fsx*

./dataleaks:
total 0
mon@razerRamon:~/tmp/DataRegister$ 

Code Snippet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
(* Ported from Haskell snippet *)
module Data =
  type 'a Sensitive =         Sensitive of 'a
  type 'a Register  = private Data      of 'a list
  
  let sensitive = Sensitive
  
  let init : unit -> 'a Register =
    fun () ->
      Data []
  
  let add : 'a -> 'a Register -> 'a Register =
    fun x (Data reg) ->
      if List.exists (fun y -> x = y) reg then
        Data reg
      else
        Data (x :: reg)
  
  let count : ('a -> bool) -> 'a Register -> int =
    fun cond (Data reg) ->
      reg
      |> List.filter cond
      |> List.length
  
  let get : ('a -> 'b) -> ('a -> bool) -> 'a Register -> 'b option =
    fun dto cond (Data reg) ->
      match List.tryFind cond reg with
        | Some x -> Some (dto x)
        | None   -> None

(* Sensitive data generator *)
module Random =
  open System
  let private r = new Random()
  let next () = r.Next()

open Data
open Random

(* Some domain type *)
type FooBar = { foo : int; bar : int Sensitive; }

let uids = [1 .. 10]

let data =
  uids
  |> List.fold(
    fun a x ->
      Data.add
        { foo = x; bar = Data.sensitive (Random.next ()) } a
  ) (Data.init())

(* Good person *)
let user1 : int option =
  data
  |> Data.get
    (fun { bar = (Sensitive num) } -> num)
    (fun x -> x.foo = 7)

(* Bad person *)
let user2 : int option =
  let leak : FooBar -> unit =
    fun { foo = uid; bar = (Sensitive num) } ->
    System.IO.File.WriteAllText(
      "./dataleaks/" + (Random.next ()).ToString() + ".log",
      sprintf "(%i,%i)\n" uid num
    )
    
  data
  |> Data.get
    (fun { FooBar.bar = (Sensitive num) } -> num)
    (fun x -> leak x; x.foo = 7)

(* 
Ensure to " ... implement appropriate TECHNICAL and organizational measures,
..., which are DESIGNED to implement data-protection principles, ..., in an
effective manner and to integrate the necessary SAFEGUARDS into the processing
in order to meet the requirements of this Regulation and protect the rights of
data subjects" (Article 25(1) EU GDPR).
*) 

Code output:

>
module Data = begin
  type 'a Sensitive = | Sensitive of 'a
  type 'a Register = private | Data of 'a list
  val sensitive : arg0:'a -> 'a Sensitive
  val init : unit -> 'a Register
  val add : x:'a -> 'a Register -> 'a Register when 'a : equality
  val count : cond:('a -> bool) -> 'a Register -> int
  val get : dto:('a -> 'b) -> cond:('a -> bool) -> 'a Register -> 'b option
end
module Random = begin
  val private r : System.Random
  val next : unit -> int
end
type FooBar =
  {foo: int;
   bar: int Data.Sensitive;}
val uids : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
val data : FooBar Data.Register
val user1 : int option = Some 235432072
val user2 : int option = Some 235432072

Data leak

mon@razerRamon:~/tmp/DataRegister$ ll -R && cat dataleaks/*
.:
total 16K
drwxrwxr-x 2 mon mon 4.0K Jul 17 13:19 dataleaks/
-rwxrwxr-x 1 mon mon 2.3K Jul 17 13:20 DataRegister.fsx*

./dataleaks:
total 48K
-rw-rw-r-- 1 mon mon 15 Jul 17 13:19 1213109609.log
-rw-rw-r-- 1 mon mon 14 Jul 17 13:19 1312310136.log
-rw-rw-r-- 1 mon mon 14 Jul 17 13:19 1690673176.log
-rw-rw-r-- 1 mon mon 14 Jul 17 13:19 801806650.log
(10,996092411)
(8,764617439)
(9,423553051)
(7,235432072)
mon@razerRamon:~/tmp/DataRegister$

References: