Skip to content

Commit

Permalink
Add Emails feature
Browse files Browse the repository at this point in the history
  • Loading branch information
yakuter committed May 29, 2020
1 parent 71cabaf commit 7a65e92
Show file tree
Hide file tree
Showing 5 changed files with 439 additions and 0 deletions.
146 changes: 146 additions & 0 deletions internal/api/email_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package api

import (
"encoding/json"
"net/http"
"strconv"

"github.com/pass-wall/passwall-server/internal/app"
"github.com/pass-wall/passwall-server/internal/storage"
"github.com/pass-wall/passwall-server/model"

"github.com/gorilla/mux"
)

// FindAllEmails ...
func FindAllEmails(s storage.Store) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var err error
emails := []model.Email{}

fields := []string{"id", "created_at", "updated_at", "email"}
argsStr, argsInt := SetArgs(r, fields)

emails, err = s.Emails().FindAll(argsStr, argsInt)
if err != nil {
RespondWithError(w, http.StatusNotFound, err.Error())
return
}

emails = app.DecryptEmailPasswords(emails)
RespondWithJSON(w, http.StatusOK, emails)
}
}

// FindEmailByID ...
func FindEmailByID(s storage.Store) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id, err := strconv.Atoi(vars["id"])
if err != nil {
RespondWithError(w, http.StatusBadRequest, err.Error())
return
}

account, err := s.Emails().FindByID(uint(id))
if err != nil {
RespondWithError(w, http.StatusNotFound, err.Error())
return
}

email, err := app.DecryptEmailPassword(s, &account)
if err != nil {
RespondWithError(w, http.StatusInternalServerError, err.Error())
return
}

RespondWithJSON(w, http.StatusOK, model.ToEmailDTO(email))
}
}

// CreateEmail ...
func CreateEmail(s storage.Store) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var emailDTO model.EmailDTO

decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&emailDTO); err != nil {
RespondWithError(w, http.StatusBadRequest, "Invalid resquest payload")
return
}
defer r.Body.Close()

createdEmail, err := app.CreateEmail(s, &emailDTO)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}

RespondWithJSON(w, http.StatusOK, model.ToEmailDTO(createdEmail))
}
}

// UpdateEmail ...
func UpdateEmail(s storage.Store) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id, err := strconv.Atoi(vars["id"])
if err != nil {
RespondWithError(w, http.StatusBadRequest, err.Error())
return
}

var emailDTO model.EmailDTO
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&emailDTO); err != nil {
RespondWithError(w, http.StatusBadRequest, "Invalid resquest payload")
return
}
defer r.Body.Close()

email, err := s.Emails().FindByID(uint(id))
if err != nil {
RespondWithError(w, http.StatusNotFound, err.Error())
return
}

updatedEmail, err := app.UpdateEmail(s, &email, &emailDTO)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}

RespondWithJSON(w, http.StatusOK, model.ToEmailDTO(updatedEmail))
}
}

// DeleteEmail ...
func DeleteEmail(s storage.Store) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id, err := strconv.Atoi(vars["id"])
if err != nil {
RespondWithError(w, http.StatusBadRequest, err.Error())
return
}

email, err := s.Emails().FindByID(uint(id))
if err != nil {
RespondWithError(w, http.StatusNotFound, err.Error())
return
}

err = s.Emails().Delete(email.ID)
if err != nil {
RespondWithError(w, http.StatusNotFound, err.Error())
return
}

response := model.Response{
Code: http.StatusOK,
Status: "Success",
Message: "Email deleted successfully!",
}
RespondWithJSON(w, http.StatusOK, response)
}
}
72 changes: 72 additions & 0 deletions internal/app/email.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package app

import (
"encoding/base64"

"github.com/pass-wall/passwall-server/internal/storage"
"github.com/pass-wall/passwall-server/model"
"github.com/spf13/viper"
)

// CreateEmail creates a new bank account and saves it to the store
func CreateEmail(s storage.Store, dto *model.EmailDTO) (*model.Email, error) {
if dto.Password == "" {
dto.Password = Password()
}

rawPass := dto.Password
dto.Password = base64.StdEncoding.EncodeToString(Encrypt(dto.Password, viper.GetString("server.passphrase")))

createdEmail, err := s.Emails().Save(*model.ToEmail(dto))
if err != nil {
return nil, err
}

createdEmail.Password = rawPass

return &createdEmail, nil
}

// UpdateEmail updates the account with the dto and applies the changes in the store
func UpdateEmail(s storage.Store, account *model.Email, dto *model.EmailDTO) (*model.Email, error) {
if dto.Password == "" {
dto.Password = Password()
}
rawPass := dto.Password
dto.Password = base64.StdEncoding.EncodeToString(Encrypt(dto.Password, viper.GetString("server.passphrase")))

dto.ID = uint(account.ID)
email := model.ToEmail(dto)
email.ID = uint(account.ID)

updatedEmail, err := s.Emails().Save(*email)
if err != nil {

return nil, err
}

updatedEmail.Password = rawPass
return &updatedEmail, nil
}

// DecryptEmailPassword decrypts password
func DecryptEmailPassword(s storage.Store, account *model.Email) (*model.Email, error) {
passByte, _ := base64.StdEncoding.DecodeString(account.Password)
account.Password = string(Decrypt(string(passByte[:]), viper.GetString("server.passphrase")))

return account, nil
}

// DecryptEmailPasswords ...
// TODO: convert to pointers
func DecryptEmailPasswords(emails []model.Email) []model.Email {
for i := range emails {
if emails[i].Password == "" {
continue
}
passByte, _ := base64.StdEncoding.DecodeString(emails[i].Password)
passB64 := string(Decrypt(string(passByte[:]), viper.GetString("server.passphrase")))
emails[i].Password = passB64
}
return emails
}
96 changes: 96 additions & 0 deletions internal/config/localization.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
tr:
# Categories
categories: Kategoriler
logins: Girişler
bank_accounts: Banka Hesapları
credit_cards: Kredi Kartları
notes: Notlar
emails: Epostalar
identities: Kimlik Bilgileri
license_keys: Lisans Anahtarları
all_items: Tüm Kayıtlar
favorites: Favoriler
trash: Çöp Kutusu

# Server
server: Sunucu
host: Sunucu Adresi
port: port
protocol: Protokol

# Lisans
license_key: Lisans Anahtarı
key: Anahtar

# Logins
url: Website Adresi

# Bank Accounts
bank_name: Banka
bank_code: Şube Kodu
account_name: Hesap İsmi
account_number: Hesap Numarası
iban: IBAN
currency: Para Birimi

# Credit Cards
card_name: Kart İsmi,
cardholder_name: Kart Sahibi
type: Tür
number: Kart Numarası
verification_number: Güvenlik Kodu
expiry_date: Son Kullanma Tarihi

# Emails
# email and password is defined in Sign in

# Notes
note: Not
notes: Notlar

# System
export: Dışa Aktar
import: İçe Aktar
backup: Yedekle
restore: Geri Yükle
select_backup: Geri yüklenecek yedeği seçin
backup_name: Yedek İsmi

# Sign in
email: Eposta Adresi
emails: Eposta Adresleri
username: Kullanıcı Adı
password: Parola
master_password: Master Parola
master_password_alert: Master parolanızı unutmayınız! Malesef bunu kurtarmak mümkün değil.
signin: Giriş
logout: Çıkış
base_url: Server Adresi
sign_to_dashboard: PassWall panele giriş yapın.

# Generic
use_this: Bunu kullan
save: Kaydet
cancel: İptal
yes: Evet
no: Hayır
refresh: Yenile
copy: Kopyala
show: Göster
hide: Gizle
delete: Sil
update: Güncelle
new: Yeni
required: Zorunlu
are_you_sure: Devam etmek istediğine emin misin?
auto_generate_password: Güçlü bir parola otomatik oluşturulsun mu?
used_password: Bu parola şu hesaplarda zaten kullanılmakta
confirm_used_password: Bu parolayı kullanmak istediğine emin misin?
created_at: Oluşturulma Tarihi
updated_at: Güncellenme Tarihi
deleted_at: Silinme Tarihi

# Errors and Success
network_error: Sunucu bağlantısında bir sorun oluştu
error: İşlem esnasında bilinmeyen bir hata ile karşılaşıldı
success: İşlem başarıyla gerçekleşti
68 changes: 68 additions & 0 deletions internal/storage/email/email_repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package email

import (
"github.com/jinzhu/gorm"
"github.com/pass-wall/passwall-server/model"
)

// Repository ...
type Repository struct {
db *gorm.DB
}

// NewRepository ...
func NewRepository(db *gorm.DB) *Repository {
return &Repository{db: db}
}

// All ...
func (p *Repository) All() ([]model.Email, error) {
emails := []model.Email{}
err := p.db.Find(&emails).Error
return emails, err
}

// FindAll ...
func (p *Repository) FindAll(argsStr map[string]string, argsInt map[string]int) ([]model.Email, error) {
emails := []model.Email{}

query := p.db
query = query.Limit(argsInt["limit"])
if argsInt["limit"] > 0 {
// offset can't be declared without a valid limit
query = query.Offset(argsInt["offset"])
}

query = query.Order(argsStr["order"])

if argsStr["search"] != "" {
query = query.Where("email LIKE ?", "%"+argsStr["search"]+"%")
}

err := query.Find(&emails).Error
return emails, err
}

// FindByID ...
func (p *Repository) FindByID(id uint) (model.Email, error) {
email := model.Email{}
err := p.db.Where(`id = ?`, id).First(&email).Error
return email, err
}

// Save ...
func (p *Repository) Save(email model.Email) (model.Email, error) {
err := p.db.Save(&email).Error
return email, err
}

// Delete ...
func (p *Repository) Delete(id uint) error {
err := p.db.Delete(&model.Email{ID: id}).Error
return err
}

// Migrate ...
func (p *Repository) Migrate() error {
return p.db.AutoMigrate(&model.Email{}).Error
}
Loading

0 comments on commit 7a65e92

Please sign in to comment.