aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/org/whispersystems/libaxolotl/state/SessionRecord.java
blob: 76c64922cd439ba79483c3488a297e19ed31dbec (plain)
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
package org.whispersystems.libaxolotl.state;

import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import static org.whispersystems.libaxolotl.state.StorageProtos.RecordStructure;
import static org.whispersystems.libaxolotl.state.StorageProtos.SessionStructure;

/**
 * A SessionRecord encapsulates the state of an ongoing session.
 *
 * @author Moxie Marlinspike
 */
public class SessionRecord {

  private static final int ARCHIVED_STATES_MAX_LENGTH = 40;

  private SessionState             sessionState   = new SessionState();
  private LinkedList<SessionState> previousStates = new LinkedList<>();
  private boolean                  fresh          = false;

  public SessionRecord() {
    this.fresh = true;
  }

  public SessionRecord(SessionState sessionState) {
    this.sessionState = sessionState;
    this.fresh        = false;
  }

  public SessionRecord(byte[] serialized) throws IOException {
    RecordStructure record = RecordStructure.parseFrom(serialized);
    this.sessionState = new SessionState(record.getCurrentSession());
    this.fresh        = false;

    for (SessionStructure previousStructure : record.getPreviousSessionsList()) {
      previousStates.add(new SessionState(previousStructure));
    }
  }

  public boolean hasSessionState(int version, byte[] aliceBaseKey) {
    if (sessionState.getSessionVersion() == version &&
        Arrays.equals(aliceBaseKey, sessionState.getAliceBaseKey()))
    {
      return true;
    }

    for (SessionState state : previousStates) {
      if (state.getSessionVersion() == version &&
          Arrays.equals(aliceBaseKey, state.getAliceBaseKey()))
      {
        return true;
      }
    }

    return false;
  }

  public SessionState getSessionState() {
    return sessionState;
  }

  /**
   * @return the list of all currently maintained "previous" session states.
   */
  public List<SessionState> getPreviousSessionStates() {
    return previousStates;
  }


  public boolean isFresh() {
    return fresh;
  }

  /**
   * Move the current {@link SessionState} into the list of "previous" session states,
   * and replace the current {@link org.whispersystems.libaxolotl.state.SessionState}
   * with a fresh reset instance.
   */
  public void archiveCurrentState() {
    promoteState(new SessionState());
  }

  public void promoteState(SessionState promotedState) {
    this.previousStates.addFirst(sessionState);
    this.sessionState = promotedState;

    if (previousStates.size() > ARCHIVED_STATES_MAX_LENGTH) {
      previousStates.removeLast();
    }
  }

  public void setState(SessionState sessionState) {
    this.sessionState = sessionState;
  }

  /**
   * @return a serialized version of the current SessionRecord.
   */
  public byte[] serialize() {
    List<SessionStructure> previousStructures = new LinkedList<>();

    for (SessionState previousState : previousStates) {
      previousStructures.add(previousState.getStructure());
    }

    RecordStructure record = RecordStructure.newBuilder()
                                            .setCurrentSession(sessionState.getStructure())
                                            .addAllPreviousSessions(previousStructures)
                                            .build();

    return record.toByteArray();
  }

}