Browse Source

initial commit; redacted out personal details for privacy concerns :-)

Taco 1 year ago
parent
commit
d373ceea0c
1 changed files with 503 additions and 0 deletions
  1. 503 0
      entitlements.org

+ 503 - 0
entitlements.org

@@ -0,0 +1,503 @@
1
+* Introduction
2
+The purpose of this document is to investigate possible User Interaction designs for Decode task 4.4.
3
+More specifically the focus is on investigating how the user of a decode wallet grants permission to decode application for a specific set of personal data.
4
+   
5
+* Data Model
6
+** Example wallet profile
7
+
8
+This sample wallet profile datastructure consists of multiple contexts.
9
+No assumptions are made about ontology for now so mention of existing e.g. skos/foaf, 
10
+everything is in the decode namespace which is well known across applications.
11
+
12
+Each context has a name and groups on or more properties that consist of a well known type and a value.
13
+A type can be part of more than one context. 
14
+#+name: profile 
15
+#+begin_src js :results output
16
+  var profile = {
17
+      contexts : 
18
+      [
19
+          {
20
+             title : "personal",
21
+              properties : 
22
+              [
23
+                  {
24
+                      type : "decode:name",
25
+                      value: "Taco van Dijk"
26
+                  },
27
+                  {
28
+                      type : "decode:email",
29
+                      value : "[REDACTED]"
30
+                  },
31
+                  {
32
+                      type: "decode:address",
33
+                      value: "[REDACTED]"
34
+                  },
35
+                  {
36
+                      type: "decode:phone",
37
+                      value : "[REDACTED]"
38
+                  }
39
+              ]
40
+          },
41
+          {
42
+              title: "professional",
43
+              properties : 
44
+              [
45
+                  {
46
+                      type : "decode:name",
47
+                      value : "Taco van Dijk"
48
+                  },
49
+                  {
50
+                      type : "decode:email",
51
+                      value : "taco@waag.org"
52
+                  },
53
+                  {
54
+                      type : "decode:address",
55
+                      value : "St. Antoniesbreestraat 69" 
56
+                  }
57
+              ]
58
+          }
59
+      ]
60
+  };
61
+  process.stdout.write(JSON.stringify(profile));
62
+#+end_src
63
+
64
+#+RESULTS: profile
65
+: {"contexts":[{"title":"personal","properties":[{"type":"decode:name","value":"Taco van Dijk"},{"type":"decode:email","value":"taco@yavin4.nl"},{"type":"decode:address","value":"Spaarndammerdijk 194"},{"type":"decode:phone","value":"0641639180"}]},{"title":"professional","properties":[{"type":"decode:name","value":"Taco van Dijk"},{"type":"decode:email","value":"taco@waag.org"},{"type":"decode:address","value":"St. Antoniesbreestraat 69"}]}]}
66
+
67
+*** Things to further investigate
68
+    - Make a big list of possible property types (at least properties that are used in Gebied Online)
69
+    - Make a big list of possible context names
70
+    - Create a generator that seeds profiles with random contexts from the aforementioned lists.
71
+    - Apply default weights to each property type, for example a high weight for the type ssn, and low for twitter@.
72
+ 
73
+** Example request 
74
+
75
+This sample application request consists of an application name, a set of required property types and a set of optional property types.
76
+
77
+#+name: request
78
+#+BEGIN_SRC js :results output
79
+  var request = {
80
+      application : "decodeapp:facebook",
81
+      required : ["decode:name", "decode:email", "decode:address"],
82
+      optional : ["decode:phone"]
83
+  }
84
+  var data = JSON.stringify(request) + "\n";
85
+  process.stdout.write(data);
86
+#+END_SRC
87
+
88
+#+RESULTS: request
89
+: {"application":"decodeapp:facebook","required":["decode:name","decode:email","decode:address"],"optional":["decode:phone"]}
90
+
91
+*** Things to further investigate
92
+    - Create a generator that seeds a request with random required and optional property types
93
+    - Add a 'sphere / context type' to each application. So tha
94
+
95
+* Data Comparison
96
+During the interaction we want to give the user insight into a couple of things;
97
+- How does the requested set of properties relate to the different contexts? How well does a context match to the request?
98
+- What would it mean for the context if the request was accepted? How many / which properties would have to be added to the context in order to fulfill the request?
99
+- What would it mean for the cumulative weight of the context?
100
+
101
+In below ruby code a comparison is made by on creating the intersection and its inverse between the request and each context.
102
+
103
+#+name: diff
104
+#+BEGIN_SRC ruby :noweb yes :var profile_data=profile :var request_data=request :results value file 
105
+  require 'json'
106
+  require 'nokogiri' #for creating xml
107
+
108
+  request = JSON.parse(request_data)
109
+  profile = JSON.parse(profile_data)
110
+
111
+  context_diffs = []
112
+  profile["contexts"].each do | context |
113
+    requested = request["required"] + request["optional"]
114
+    available = context["properties"].map {|p| p["type"]}
115
+
116
+    intersect = available & requested
117
+    except = requested - available
118
+    diff = {:context => context["title"], :intersect => intersect, :except => except}
119
+
120
+    context_diffs << diff
121
+  end
122
+
123
+  <<xml>>
124
+#+END_SRC
125
+
126
+#+RESULTS: diff
127
+[[file:diff.xml]]
128
+
129
+*** Things to further investigate
130
+    - Calculate the weight of each context before and after giving permission
131
+
132
+NOTE: We export to file diff.xml here for easy parsing in processing.js below.
133
+
134
+#+name: xml 
135
+#+BEGIN_SRC ruby :exports none
136
+  # unfortunately processing.js doesn't support json yet, so we have to use xml
137
+  doc = Nokogiri::XML::Builder.new do |xml|
138
+  xml.result {
139
+    xml.request { 
140
+      xml.application request["application"] 
141
+      xml.required {
142
+        request["required"].each do |p| xml.property p end
143
+      } 
144
+      xml.optional {
145
+        request["optional"].each do |p| xml.property p end
146
+      }
147
+    }
148
+    xml.diffs {
149
+      context_diffs.each do |diff|
150
+       xml.diff {
151
+        xml.contextName diff[:context]
152
+        xml.intersect {
153
+          diff[:intersect].each do |p| xml.property p end
154
+        }
155
+        xml.except {
156
+          diff[:except].each do |p| xml.property p end
157
+        }
158
+       }
159
+      end
160
+    }
161
+  }
162
+  end
163
+  path = "diff.xml"
164
+  File.write(path, doc.to_xml) 
165
+  path
166
+  #+END_SRC
167
+
168
+/de relatieve grootte van de cirkel kan zijn op basis van hoeveel data je erin hebt. 
169
+personal is size 4, professional size 3
170
+request is size 3
171
+
172
+* Visualization
173
+
174
+We want to visualize the following things;
175
+- The request with the application name and it's size / quality (Who's asking what)
176
+- The different contexts with it's name and size / quality relative to the request. (What would it mean to accept?)
177
+
178
+Per the design of Dyne, we want to use color to indicate the relation between the request and each context.
179
+- 
180
+
181
+#+name: glue 
182
+#+BEGIN_SRC processing :exports none 
183
+class Request
184
+{
185
+  public String application;
186
+  public String[] required_properties;
187
+  public String[] optional_properties;
188
+
189
+  public Request(String app, String[] req, String[] opt)
190
+  {
191
+    this.application = app;
192
+    this.required_properties = req;
193
+    this.optional_properties = opt;
194
+  }
195
+}
196
+
197
+class Diff
198
+{
199
+  public String context;
200
+  public String[] intersect;
201
+  public String[] except;
202
+
203
+  public Diff(String ctx, String[] intersect, String[] except)
204
+  {
205
+    this.context = ctx;
206
+    this.intersect = intersect;
207
+    this.except = except;
208
+  } 
209
+}
210
+
211
+XMLElement doc = new XMLElement(this, 'diff.xml');
212
+//create typed versions because this is java :-(
213
+void parseRequest(xml)
214
+{
215
+  XMLElement req = xml.getChild(0);
216
+  String name = req.getChild(0).getContent();
217
+  String[] required = new String[req.getChild(1).getChildCount()];
218
+  String[] optional = new String[req.getChild(2).getChildCount()];
219
+  
220
+  for (int i = 0; i < required.length; i++) {
221
+    required[i] = req.getChild(1).getChild(i).getContent();
222
+  }
223
+
224
+  for (int i = 0; i < optional.length; i++) {
225
+    optional[i] = req.getChild(2).getChild(i).getContent();
226
+  }
227
+
228
+  Request r = new Request(name,required,optional);
229
+  return r;
230
+}
231
+
232
+//create typed versions because this is java :-(
233
+void parseDiffs(xml)
234
+{
235
+  XMLElement diffsEl = xml.getChild(1);
236
+  Diff[] diffs = new Diff[diffsEl.getChildCount()];
237
+  for(int i = 0; i < diffs.length; i++)
238
+  {
239
+    String contextName = diffsEl.getChild(i).getChild(0).getContent();
240
+    String[] intersects = new String[diffsEl.getChild(i).getChild(1).getChildCount()];
241
+    String[] except = new String[diffsEl.getChild(i).getChild(2).getChildCount()];
242
+    
243
+    for(int j = 0; j < intersects.length; j++)
244
+    {
245
+      intersects[j] = diffsEl.getChild(i).getChild(1).getChild(j).getContent();
246
+    }
247
+
248
+    for(int j = 0; j < except.length; j++)
249
+    {
250
+      except[j] = diffsEl.getChild(i).getChild(2).getChild(j).getContent();
251
+    }
252
+
253
+    Diff diff = new Diff(contextName,intersects,except);
254
+    diffs[i] = diff;
255
+  }
256
+  return diffs;
257
+}
258
+#+END_SRC
259
+
260
+** Request
261
+#+name: draw_request
262
+#+BEGIN_SRC processing :noweb yes
263
+<<glue>>
264
+Request r = parseRequest(doc);
265
+Diff[] d = parseDiffs(doc);
266
+//set up font for labels
267
+//PFont label_font = createFont("Arial",16,true);
268
+//textFont(label_font,12);
269
+
270
+//draw the difference for each context with the request
271
+size(200,200);
272
+background(0);
273
+noFill();
274
+stroke(255);
275
+ellipse(56, 46, 55, 55);
276
+//fill(255);
277
+text(r.application, 10, 10);
278
+#+END_SRC
279
+
280
+#+RESULTS: draw_request
281
+#+BEGIN_EXPORT html
282
+<script src="processing.js"></script>
283
+ <script type="text/processing" data-processing-target="ob-358673b6aca53ef65765ed4baecf23b8c3889682">
284
+class Request
285
+{
286
+  public String application;
287
+  public String[] required_properties;
288
+  public String[] optional_properties;
289
+
290
+  public Request(String app, String[] req, String[] opt)
291
+  {
292
+    this.application = app;
293
+    this.required_properties = req;
294
+    this.optional_properties = opt;
295
+  }
296
+}
297
+
298
+class Diff
299
+{
300
+  public String context;
301
+  public String[] intersect;
302
+  public String[] except;
303
+
304
+  public Diff(String ctx, String[] intersect, String[] except)
305
+  {
306
+    this.context = ctx;
307
+    this.intersect = intersect;
308
+    this.except = except;
309
+  } 
310
+}
311
+
312
+XMLElement doc = new XMLElement(this, 'diff.xml');
313
+//create typed versions because this is java :-(
314
+void parseRequest(xml)
315
+{
316
+  XMLElement req = xml.getChild(0);
317
+  String name = req.getChild(0).getContent();
318
+  String[] required = new String[req.getChild(1).getChildCount()];
319
+  String[] optional = new String[req.getChild(2).getChildCount()];
320
+  
321
+  for (int i = 0; i < required.length; i++) {
322
+    required[i] = req.getChild(1).getChild(i).getContent();
323
+  }
324
+
325
+  for (int i = 0; i < optional.length; i++) {
326
+    optional[i] = req.getChild(2).getChild(i).getContent();
327
+  }
328
+
329
+  Request r = new Request(name,required,optional);
330
+  return r;
331
+}
332
+
333
+//create typed versions because this is java :-(
334
+void parseDiffs(xml)
335
+{
336
+  XMLElement diffsEl = xml.getChild(1);
337
+  Diff[] diffs = new Diff[diffsEl.getChildCount()];
338
+  for(int i = 0; i < diffs.length; i++)
339
+  {
340
+    String contextName = diffsEl.getChild(i).getChild(0).getContent();
341
+    String[] intersects = new String[diffsEl.getChild(i).getChild(1).getChildCount()];
342
+    String[] except = new String[diffsEl.getChild(i).getChild(2).getChildCount()];
343
+    
344
+    for(int j = 0; j < intersects.length; j++)
345
+    {
346
+      intersects[j] = diffsEl.getChild(i).getChild(1).getChild(j).getContent();
347
+    }
348
+
349
+    for(int j = 0; j < except.length; j++)
350
+    {
351
+      except[j] = diffsEl.getChild(i).getChild(2).getChild(j).getContent();
352
+    }
353
+
354
+    Diff diff = new Diff(contextName,intersects,except);
355
+    diffs[i] = diff;
356
+  }
357
+  return diffs;
358
+}
359
+Request r = parseRequest(doc);
360
+Diff[] d = parseDiffs(doc);
361
+//set up font for labels
362
+//PFont label_font = createFont("Arial",16,true);
363
+//textFont(label_font,12);
364
+
365
+//draw the difference for each context with the request
366
+size(200,200);
367
+background(0);
368
+noFill();
369
+stroke(255);
370
+ellipse(56, 46, 55, 55);
371
+//fill(255);
372
+text(r.application, 10, 10);
373
+</script> <canvas id="ob-358673b6aca53ef65765ed4baecf23b8c3889682"></canvas>
374
+#+END_EXPORT
375
+
376
+** Contexts
377
+   How do we visulize each context? Intend to do this in processing too.
378
+#+name: draw_context
379
+#+BEGIN_SRC processing :noweb yes
380
+<<glue>>
381
+Request r = parseRequest(doc);
382
+Diff[] d = parseDiffs(doc);
383
+//set up font for labels
384
+//PFont label_font = createFont("Arial",16,true);
385
+//textFont(label_font,12);
386
+
387
+//draw the difference for each context with the request
388
+size(200,200);
389
+background(0);
390
+noFill();
391
+stroke(255);
392
+ellipse(56, 46, 55, 55);
393
+//fill(255);
394
+text(d[0].context, 10, 10);
395
+#+END_SRC
396
+
397
+#+RESULTS: draw_context
398
+#+BEGIN_EXPORT html
399
+<script src="processing.js"></script>
400
+ <script type="text/processing" data-processing-target="ob-efa176753d914243c7a44088a4a08201dd1f5913">
401
+class Request
402
+{
403
+  public String application;
404
+  public String[] required_properties;
405
+  public String[] optional_properties;
406
+
407
+  public Request(String app, String[] req, String[] opt)
408
+  {
409
+    this.application = app;
410
+    this.required_properties = req;
411
+    this.optional_properties = opt;
412
+  }
413
+}
414
+
415
+class Diff
416
+{
417
+  public String context;
418
+  public String[] intersect;
419
+  public String[] except;
420
+
421
+  public Diff(String ctx, String[] intersect, String[] except)
422
+  {
423
+    this.context = ctx;
424
+    this.intersect = intersect;
425
+    this.except = except;
426
+  } 
427
+}
428
+
429
+XMLElement doc = new XMLElement(this, 'diff.xml');
430
+//create typed versions because this is java :-(
431
+void parseRequest(xml)
432
+{
433
+  XMLElement req = xml.getChild(0);
434
+  String name = req.getChild(0).getContent();
435
+  String[] required = new String[req.getChild(1).getChildCount()];
436
+  String[] optional = new String[req.getChild(2).getChildCount()];
437
+  
438
+  for (int i = 0; i < required.length; i++) {
439
+    required[i] = req.getChild(1).getChild(i).getContent();
440
+  }
441
+
442
+  for (int i = 0; i < optional.length; i++) {
443
+    optional[i] = req.getChild(2).getChild(i).getContent();
444
+  }
445
+
446
+  Request r = new Request(name,required,optional);
447
+  return r;
448
+}
449
+
450
+//create typed versions because this is java :-(
451
+void parseDiffs(xml)
452
+{
453
+  XMLElement diffsEl = xml.getChild(1);
454
+  Diff[] diffs = new Diff[diffsEl.getChildCount()];
455
+  for(int i = 0; i < diffs.length; i++)
456
+  {
457
+    String contextName = diffsEl.getChild(i).getChild(0).getContent();
458
+    String[] intersects = new String[diffsEl.getChild(i).getChild(1).getChildCount()];
459
+    String[] except = new String[diffsEl.getChild(i).getChild(2).getChildCount()];
460
+    
461
+    for(int j = 0; j < intersects.length; j++)
462
+    {
463
+      intersects[j] = diffsEl.getChild(i).getChild(1).getChild(j).getContent();
464
+    }
465
+
466
+    for(int j = 0; j < except.length; j++)
467
+    {
468
+      except[j] = diffsEl.getChild(i).getChild(2).getChild(j).getContent();
469
+    }
470
+
471
+    Diff diff = new Diff(contextName,intersects,except);
472
+    diffs[i] = diff;
473
+  }
474
+  return diffs;
475
+}
476
+Request r = parseRequest(doc);
477
+Diff[] d = parseDiffs(doc);
478
+//set up font for labels
479
+//PFont label_font = createFont("Arial",16,true);
480
+//textFont(label_font,12);
481
+
482
+//draw the difference for each context with the request
483
+size(200,200);
484
+background(0);
485
+noFill();
486
+stroke(255);
487
+ellipse(56, 46, 55, 55);
488
+//fill(255);
489
+text(d[0].context, 10, 10);
490
+</script> <canvas id="ob-efa176753d914243c7a44088a4a08201dd1f5913"></canvas>
491
+#+END_EXPORT
492
+
493
+*** Things to further investigate
494
+    - How do we show relation between request and each context with color?
495
+    - Can we use distance as well as color to indicate the relation?
496
+    - Can we use size of the circle to indicate the weight, or use badges?
497
+
498
+* Interaction
499
+We intend to investigate this in Processing as well.
500
+
501
+*** Things to further investigate
502
+    - How does the end user actually accept the request? Is it by dragging the request onto the context?
503
+    - How does the end user decline the request?