Skip to content

Commit

Permalink
adds message share and decryption e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ivarprudnikov committed Apr 23, 2024
1 parent 6e0a3c2 commit e8a6541
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 41 deletions.
1 change: 0 additions & 1 deletion cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
module.exports = {
fixturesFolder: false,
e2e: {
supportFile: false,
baseUrl: 'http://localhost:8080',
},
}
18 changes: 3 additions & 15 deletions cypress/e2e/auth.cy.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
describe('auth spec', () => {
it('can login with a preconfigured account', () => {
cy.visit('/accounts/login')
cy.get('#username').type('joe')
cy.get('#password').type('joe')
cy.get('.btn-primary').click()
cy.contains('footer', 'User: joe').should('be.visible')
cy.loginJoe()
cy.clearCookies()
})
it('can logout after logging in', () => {
cy.visit('/accounts/login')
cy.get('#username').type('joe')
cy.get('#password').type('joe')
cy.get('.btn-primary').click()
cy.contains('footer', 'User: joe').should('be.visible')

cy.loginJoe()
cy.contains('header a', 'Logout').should('be.visible')
cy.get('.logout-link').click()

cy.logout()
cy.contains('footer', 'User: joe').should('not.exist')

cy.clearCookies()
})
it('creates account and can login', () => {
Cypress.Cookies.debug(true)
Expand Down
119 changes: 105 additions & 14 deletions cypress/e2e/messages.cy.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,115 @@
describe('messages spec', () => {
it('joe can see his message in the list', () => {
cy.visit('/accounts/login')
cy.get('#username').type('joe')
cy.get('#password').type('joe')
cy.get('.btn-primary').click()
cy.contains('footer', 'User: joe').should('be.visible')

cy.loginJoe()
cy.visit('/messages')
cy.contains('h1', 'Messages').should('be.visible')
cy.get('.message-row').should('have.length', 1)
})
it('alice does not have messages', () => {
cy.visit('/accounts/login')
cy.get('#username').type('alice')
cy.get('#password').type('alice')
cy.get('.btn-primary').click()
cy.contains('footer', 'User: alice').should('be.visible')
it('joe can share his message with anonymous user', () => {
cy.loginJoe()

cy.visit('/messages')
cy.contains('h1', 'Messages').should('be.visible')
cy.get('.message-row').should('have.length', 0)
cy.get('.message-row a')
.should('have.attr', 'href')
.then(($href) => {
cy.logout()
cy.visit($href)

cy.contains('h1', 'Secret message').should('be.visible')
})
})

it('alice creates a message, shares it and annon can decrypt it, then message is deleted', function() {

cy.loginAlice()

// create a message
cy.get('.nav-link.messages-new').click()
cy.contains('h3', 'Create new').should('be.visible')
cy.get('#payload').type('foobar')
cy.get('.btn-primary').click()
cy.contains('h5', 'Message securely stored').should('be.visible')
cy.get('.message-pin')
.invoke('text')
.then(parseFloat)
.as('pinval')
cy.get('@pinval').should('be.gte', 100)
cy.get('.message-link').should('have.attr', 'href')
.as('messageHref')
.then(($href) => {
cy.logout()
})

cy.get('@messageHref').then($href => {
cy.get('@pinval').then((pinval) => {
cy.enterPin($href, pinval)
})
})

cy.contains('.message-content-decrypted', 'foobar').should('be.visible')
cy.get('input#pin').should('not.exist')

cy.get('@messageHref')
.then(($href) => {
cy.visit($href, {failOnStatusCode: false})
cy.contains('h1', '404: Page not found').should('be.visible')
})
})

it('new message gets deleted after unuccessful PIN attempts', function() {

Cypress.Cookies.debug(true)

cy.loginAlice()

// create a message
cy.get('.nav-link.messages-new').click()
cy.contains('h3', 'Create new').should('be.visible')
cy.get('#payload').type('foobar')
cy.get('.btn-primary').click()
cy.contains('h5', 'Message securely stored').should('be.visible')
cy.get('.message-pin')
.invoke('text')
.then(parseFloat)
.as('pinval')
cy.get('@pinval').should('be.gte', 100)
cy.get('.message-link').should('have.attr', 'href')
.as('messageHref')
.then(($href) => {
cy.logout()
})

// pin attempt
cy.get('@messageHref').then($href => {
cy.enterPin($href, '0000')
})
cy.contains('p', 'failed to get a message').should('be.visible')
// pin attempt
cy.get('@messageHref').then($href => {
cy.enterPin($href, '0000')
})
cy.contains('p', 'failed to get a message').should('be.visible')
// pin attempt
cy.get('@messageHref').then($href => {
cy.enterPin($href, '0000')
})
cy.contains('p', 'failed to get a message').should('be.visible')
// pin attempt
cy.get('@messageHref').then($href => {
cy.enterPin($href, '0000')
})
cy.contains('p', 'failed to get a message').should('be.visible')
// pin attempt
cy.get('@messageHref').then($href => {
cy.enterPin($href, '0000')
})
cy.contains('p', 'failed to get a message').should('be.visible')
// message should have been deleted
cy.get('@messageHref').then($href => {
cy.visit($href, {failOnStatusCode: false})
cy.contains('h1', '404: Page not found').should('be.visible')
})

})

})
27 changes: 27 additions & 0 deletions cypress/support/e2e.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Cypress.Commands.add('loginJoe', () => {
cy.visit('/accounts/login')
cy.get('#username').type('joe')
cy.get('#password').type('joe')
cy.get('.btn-primary').click()
cy.contains('footer', 'User: joe').should('be.visible')
})
Cypress.Commands.add('loginAlice', () => {
cy.visit('/accounts/login')
cy.get('#username').type('alice')
cy.get('#password').type('alice')
cy.get('.btn-primary').click()
cy.contains('footer', 'User: alice').should('be.visible')
})
Cypress.Commands.add('logout', () => {
cy.get('.logout-link').click()
cy.contains('footer', 'User:').should('not.exist')
cy.clearCookies()
})
Cypress.Commands.add('enterPin', (requestPath, pinval) => {
cy.visit(requestPath)
// somehow csrf cookie value is not correctly set by cypress after "visit"
cy.reload()
cy.contains('h1', 'Secret message').should('be.visible')
cy.get('input#pin').should('be.visible').type(pinval)
cy.get('.btn-primary').click()
})
2 changes: 1 addition & 1 deletion internal/storage/memstore/messages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func TestMessageStore_GetFullMessage(t *testing.T) {
t.Fatalf("Expected content %s, got %s", content, foundMsg.Content)
}

// Mesage was deleted after access
// Message was deleted after access
msgs, err := store.ListMessages("testuser")
if err != nil {
t.Fatalf("Expected no error, got %v", err)
Expand Down
6 changes: 5 additions & 1 deletion routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,10 @@ func showMsgFullHandler(sessions *sessions.CookieStore, store storage.MessageSto
return
}
csrf := r.PostForm.Get("_csrf")
if csrf == "" || csrf != sess.Values[SESS_CSRF_KEY] {
csrfReal := sess.Values[SESS_CSRF_KEY].(string)
slog.LogAttrs(r.Context(), slog.LevelDebug, "csrf token in the session", slog.String("csrf", csrfReal))
slog.LogAttrs(r.Context(), slog.LevelDebug, "csrf token in the post form", slog.String("csrf", csrf))
if csrf == "" || csrf != csrfReal {
slog.LogAttrs(r.Context(), slog.LevelError, "invalid csrf token")
sendError(r.Context(), sess, w, "failed to get a message", nil)
return
Expand Down Expand Up @@ -321,6 +324,7 @@ func newAppMiddleware(sessions *sessions.CookieStore, users storage.UserStore) f
return
}
sess.Values[SESS_CSRF_KEY] = t
slog.LogAttrs(r.Context(), slog.LevelDebug, "csrf token generated", slog.String("csrf", t))
}

// check if user is set, if yes then add it to context
Expand Down
6 changes: 3 additions & 3 deletions web/message.created.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@

<div class="card text-center">
<div class="card-body">
<h5 class="card-title">Mesage securely stored!</h5>
<h5 class="card-title">Message securely stored!</h5>
<h6 class="card-subtitle mb-2 text-body-secondary">Now, write down the PIN!</h6>
<p class="card-text">
This is the only time you will see the generated PIN. The PIN will decrypt the message:
</p>
<p class="fw-bold text-center fs-2">
<p class="fw-bold text-center fs-2 message-pin">
{{.data.Pin}}
</p>
<a href="/messages/{{ .data.PartitionKey }}" class="card-link">Link to the message</a>
<a href="/messages/{{ .data.PartitionKey }}" class="card-link message-link">Link to the message</a>
</div>
</div>

Expand Down
2 changes: 1 addition & 1 deletion web/message.show.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

{{if .data.Pin}}
<h3>Content</h3>
<p>{{.data.Content}}</p>
<p class="message-content-decrypted">{{.data.Content}}</p>
{{else}}
<h3>Content</h3>
<svg width="100" height="100" class="bi mt-4 mb-3" style="color: var(--bs-indigo);" xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M240-80q-33 0-56.5-23.5T160-160v-400q0-33 23.5-56.5T240-640h40v-80q0-83 58.5-141.5T480-920q83 0 141.5 58.5T680-720v80h40q33 0 56.5 23.5T800-560v400q0 33-23.5 56.5T720-80H240Zm0-80h480v-400H240v400Zm240-120q33 0 56.5-23.5T560-360q0-33-23.5-56.5T480-440q-33 0-56.5 23.5T400-360q0 33 23.5 56.5T480-280ZM360-640h240v-80q0-50-35-85t-85-35q-50 0-85 35t-35 85v80ZM240-160v-400 400Z"/></svg>
Expand Down
10 changes: 5 additions & 5 deletions web/nav.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
</a>

<ul class="nav nav-pills">
<li class="nav-item"><a href="/" class="nav-link">Home</a></li>
<li class="nav-item"><a href="/" class="nav-link home-link">Home</a></li>
{{if .session.user }}
<li class="nav-item"><a href="/messages" class="nav-link">Messages</a></li>
<li class="nav-item"><a href="/messages/new" class="nav-link">Create new</a></li>
<li class="nav-item"><a href="/messages" class="nav-link messages-list">Messages</a></li>
<li class="nav-item"><a href="/messages/new" class="nav-link messages-new">Create new</a></li>
<li class="nav-item"><a href="/accounts/logout" class="nav-link logout-link">Logout</a></li>
{{else}}
<li class="nav-item"><a href="/accounts/login" class="nav-link">Login</a></li>
<li class="nav-item"><a href="/accounts/new" class="nav-link">Sign up</a></li>
<li class="nav-item"><a href="/accounts/login" class="nav-link login-link">Login</a></li>
<li class="nav-item"><a href="/accounts/new" class="nav-link signup-link">Sign up</a></li>
{{end}}
</ul>
</header>

0 comments on commit e8a6541

Please sign in to comment.