-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFileSharing1.als
More file actions
190 lines (160 loc) · 4.42 KB
/
FileSharing1.als
File metadata and controls
190 lines (160 loc) · 4.42 KB
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
module Apps/FileSharing1
open Action
open Reaction
// Composed concepts
open Concepts/Trash[File]
open Concepts/Permalink[File,Token]
one sig T extends Trash {}
one sig P extends Permalink {}
// Types
sig File {}
sig Token {}
// App specific views of the state of the concepts to simplify the specification and visualization
fun uploaded : set File { T.accessible + T.trashed }
fun trashed : set File { T.trashed }
fun shared : File -> Token { P.urls :> (Token - P.revoked) }
// App specific action names
pred upload[f : File] { T.create[f] }
pred delete[f : File] { T.delete[f] }
pred restore[f : File] { T.restore[f] }
pred empty { T.empty }
pred share[f : File, t : Token] { P.share[f,t] }
pred download[t : Token] { P.access[t] }
// The design goal
// The shared tokes are those that have been shared while the respective file was accessible
// and not deleted nor downloaded afterwards
check Design {
always {
no reactions iff {
shared = { f : File, t : Token | before (not (delete[f] or download[t]) since (share[f,t] and f in uploaded - trashed))}
}
}
} for 2 but 10 Action, 10 Reaction expect 0
// Additional properties
check Invariant {
always {
no reactions implies {
shared.Token in uploaded - trashed
accessed in revoked
}
}
} for 2 but 10 Action, 10 Reaction expect 0
// Expected revoked value
check Revoked {
always {
no reactions implies {
P.revoked = { t : Token | before once (download[t] or some f : File | t in f.shared and delete[f]) }
}
}
} for 2 but 10 Action, 10 Reaction expect 0
// Downloaded files must be uploaded and not trashed
check DownloadedAreAccessible {
all t : Token | always {
download[t] implies shared.t in uploaded - trashed
}
} for 2 but 10 Action, 10 Reaction expect 0
// Tokens can only be accessed once
check SingleAccess {
all t : Token | always {
download[t] implies before historically not download[t]
}
} for 2 but 10 Action, 10 Reaction expect 0
// Scenarios
// A file is uploaded, shared twice, accessed, and deleted. Reactions should revoke all tokens.
run Scenario1 {
some f : File, t,u : Token {
upload[f]; share[f,t]; share[f,u]; download[u]; some reactions; delete[f]
}
eventually always no reactions
} for exactly 1 File, 2 Token, 10 Action, 10 Reaction expect 1
// A file is uploaded, shared, and deleted.
// Then, when the reactions are finished one tries to access the token, which should not be possible.
run Scenario2 {
some f : File, t : Token {
upload[f]; share[f,t]; delete[f]; eventually download[t]
}
eventually always no reactions
} for exactly 1 File, exactly 1 Token, 10 Action, 10 Reaction expect 0
// A file is uploaded and shared.
// Then one tries to revoke the token, which should not be possible.
run Scenario3 {
some f : File, t : Token {
upload[f]; share[f,t]; P.revoke[t]
}
eventually always no reactions
} for exactly 1 File, exactly 1 Token, 10 Action, 10 Reaction expect 0
// Reactions
/*
reaction delete_revoke
when
T.delete[f]
where
t in f.shared
then
P.revoke[t]
*/
sig Delete_Revoke extends Reaction { token : Token }
fact {
all x,y : Delete_Revoke | x.token = y.token implies x = y
}
fact {
all t : Token | always {
(some d : Delete_Revoke & reactions_to_add | d.token = t) iff (some f : File | T.delete[f] and t in f.shared)
(some d : Delete_Revoke & reactions_to_remove | d.token = t) iff P.revoke[t]
}
}
/*
reaction access_revoke
when
P.access[t]
then
P.revoke[t]
*/
sig Access_Revoke extends Reaction { token : Token }
fact {
all x,y : Access_Revoke | x.token = y.token implies x = y
}
fact {
all t : Token | always {
(some d : Access_Revoke & reactions_to_add | d.token = t) iff P.access[t]
(some d : Access_Revoke & reactions_to_remove | d.token = t) iff P.revoke[t]
}
}
/*
reaction share_error
when
P.share[f,t]
where
f not in uploaded - T.trashed
then
error
*/
sig Share_Error extends Reaction {}
fact {
all x,y : Share_Error | x = y
}
fact {
always {
some Share_Error & reactions_to_add iff (some f : File, t : Token | P.share[f,t] and f not in uploaded - T.trashed)
some Share_Error & reactions_to_remove iff error
}
}
/*
reaction revoke_error
when
P.revoke[t]
where
t not in P.accessed and shared.t not in T.trashed
then
error
*/
sig Revoke_Error extends Reaction {}
fact {
all x,y : Revoke_Error | x = y
}
fact {
always {
some Revoke_Error & reactions_to_add iff (some t : Token | P.revoke[t] and t not in P.accessed and shared.t not in T.trashed)
some Revoke_Error & reactions_to_remove iff error
}
}