Skip to content

Commit

Permalink
moving topic initialization to a saparate file to simplify refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
or-else committed May 31, 2019
1 parent ae93511 commit 6c639a7
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 603 deletions.
13 changes: 8 additions & 5 deletions docs/API.md
Expand Up @@ -5,16 +5,17 @@
- [General considerations](#general-considerations)
- [Connecting to the server](#connecting-to-the-server)
- [gRPC](#grpc)
- [Websocket](#websocket)
- [WebSocket](#websocket)
- [Long polling](#long-polling)
- [Out of Band Large Files](#out-of-band-large-files)
- [Users](#users)
- [Authentication](#authentication)
- [Creating an Account](#creating-an-account)
- [Logging in](#logging-in)
- [Changing Authentication Parameters](#changing-authentication-parameters)
- [Resetting a Password](#resetting-a-password)
- [Resetting a Password, i.e. "Forgot Password"](#resetting-a-password-ie-forgot-password)
- [Credentials](#credentials)
- [Changing Credentials](#changing-credentials)
- [Access control](#access-control)
- [Topics](#topics)
- [`me` topic](#me-topic)
Expand Down Expand Up @@ -197,7 +198,8 @@ User may change authentication parameters, such as changing login and password,
acc: {
id: "1a2b3", // string, client-provided message id, optional
user: "usr2il9suCbuko", // user being affected by the change, optional
token: "XMg...g1Gp8+BO0=", // authentication token if the session is not yet authenticated, optional.
token: "XMg...g1Gp8+BO0=", // authentication token if the session
// is not yet authenticated, optional.
scheme: "basic", // authentication scheme being updated.
secret: base64encode("new_username:new_password") // new parameters
}
Expand Down Expand Up @@ -236,7 +238,8 @@ Credentials can be added or deleted by sending an `{acc}` message:
acc: {
id: "1a2b3", // string, client-provided message id, optional
user: "usr2il9suCbuko", // user being affected by the change, optional
token: "XMg...g1Gp8+BO0=", // authentication token if the session is not yet authenticated, optional.
token: "XMg...g1Gp8+BO0=", // authentication token if the session is
// not yet authenticated, optional.
cred: [
{
meth: "email", // string, verification method, e.g. "email", "tel", "recaptcha", etc.
Expand All @@ -250,7 +253,7 @@ acc: {
```
To remove an existing credential set `resp` to a single Unicode DEL character "␡" (`\u2421`): `resp: "␡"`.

If certain credentials are required, then the user must maintain them at all times. It means if a required credential has to be changed, the user must first add and validate a new credential, then remove the old one.
If certain credentials are required, then user must maintain them in validated state at all times. It means if a required credential has to be changed, the user must first add and validate the new credential and only then remove the old one.


### Access control
Expand Down
8 changes: 4 additions & 4 deletions server/db/adapter.go
Expand Up @@ -52,13 +52,13 @@ type Adapter interface {

// Credential management

// CredAdd adds credential record.
// CredAdd adds a credential record.
CredAdd(cred *t.Credential) error
// CredGet returns credential record.
// CredGet returns all credential records for the given method.
CredGet(uid t.Uid, method string) ([]*t.Credential, error)
// CredIsConfirmed returns true if the given credential has been verified, false otherwise.
// CredIsConfirmed returns true if the given credential method has been verified, false otherwise.
CredIsConfirmed(uid t.Uid, metod string) (bool, error)
// CredDel deletes given credential.
// CredDel deletes credentials for the given method. If method is empty, deletes all user's credentials.
CredDel(uid t.Uid, method string) error
// CredConfirm marks given credential as validated.
CredConfirm(uid t.Uid, method string) error
Expand Down
28 changes: 21 additions & 7 deletions server/db/mysql/adapter.go
Expand Up @@ -633,7 +633,7 @@ func (a *adapter) UserGetAll(ids ...t.Uid) ([]t.User, error) {
}

users := []t.User{}
q, _, _ := sqlx.In("SELECT * FROM users WHERE id IN (?) AND deletedat IS NULL", uids)
q, uids, _ := sqlx.In("SELECT * FROM users WHERE id IN (?) AND deletedat IS NULL", uids)
q = a.db.Rebind(q)
rows, err := a.db.Queryx(q, uids...)
if err != nil {
Expand Down Expand Up @@ -1126,7 +1126,7 @@ func (a *adapter) TopicsForUser(uid t.Uid, keepDeleted bool, opts *t.QueryOpt) (

if len(topq) > 0 {
// Fetch grp & p2p topics
q, _, _ := sqlx.In(
q, topq, _ := sqlx.In(
"SELECT createdat,updatedat,deletedat,touchedat,name AS id,access,seqid,delid,public,tags "+
"FROM topics WHERE name IN (?)", topq)
q = a.db.Rebind(q)
Expand Down Expand Up @@ -1159,7 +1159,7 @@ func (a *adapter) TopicsForUser(uid t.Uid, keepDeleted bool, opts *t.QueryOpt) (

// Fetch p2p users and join to p2p tables
if err == nil && len(usrq) > 0 {
q, _, _ := sqlx.In(
q, usrq, _ := sqlx.In(
"SELECT id,state,createdat,updatedat,deletedat,access,lastseen,useragent,public,tags FROM users WHERE id IN (?)",
usrq)
rows, err = a.db.Queryx(q, usrq...)
Expand Down Expand Up @@ -2065,7 +2065,7 @@ func (a *adapter) DeviceGetAll(uids ...t.Uid) (map[t.Uid][]t.DeviceDef, int, err
unums = append(unums, store.DecodeUid(uid))
}

q, _, _ := sqlx.In("SELECT userid,deviceid,platform,lastseen,lang FROM devices WHERE userid IN (?)", unums)
q, unums, _ := sqlx.In("SELECT userid,deviceid,platform,lastseen,lang FROM devices WHERE userid IN (?)", unums)
rows, err := a.db.Queryx(q, unums...)
if err != nil {
return nil, 0, err
Expand Down Expand Up @@ -2131,6 +2131,8 @@ func (a *adapter) DeviceDelete(uid t.Uid, deviceID string) error {
}

// Credential management

// CredAdd adds credential validation record: userd ID, method, credential value, possible response.
func (a *adapter) CredAdd(cred *t.Credential) error {
// Enforce uniqueness: if credential is confirmed, "method:value" must be unique.
// if credential is not yet confirmed, "userid:method:value" is unique.
Expand All @@ -2148,9 +2150,11 @@ func (a *adapter) CredAdd(cred *t.Credential) error {
return err
}

// CredIsConfirmed returns true of the given validation method is confirmed.
func (a *adapter) CredIsConfirmed(uid t.Uid, method string) (bool, error) {
var done int
err := a.db.Get(&done, "SELECT done FROM credentials WHERE userid=? AND method=?",
// There could be more than one credential of the same method. We just need one.
err := a.db.Get(&done, "SELECT done FROM credentials WHERE userid=? AND method=? AND done=1",
store.DecodeUid(uid), method)
if err == sql.ErrNoRows {
// Nothing found, clear the error, otherwise it will be reported as internal error.
Expand All @@ -2160,7 +2164,9 @@ func (a *adapter) CredIsConfirmed(uid t.Uid, method string) (bool, error) {
return done > 0, err
}

// credDel deletes given validation method or ll methods of the given user.
func credDel(tx *sqlx.Tx, uid t.Uid, method string) error {
// FIXME: There could be more than one credential of the same method.
query := "DELETE FROM credentials WHERE userid=?"
args := []interface{}{store.DecodeUid(uid)}
if method != "" {
Expand All @@ -2171,7 +2177,10 @@ func credDel(tx *sqlx.Tx, uid t.Uid, method string) error {
return err
}

// CredDel deletes either all credentials of the given user and method
// or all credentials of the given user if the method is blank.
func (a *adapter) CredDel(uid t.Uid, method string) error {
// FIXME: There could be more than one credential of the same method.
tx, err := a.db.Beginx()
if err != nil {
return err
Expand All @@ -2190,7 +2199,9 @@ func (a *adapter) CredDel(uid t.Uid, method string) error {
return tx.Commit()
}

// CredConfirm marks given credential method as confirmed.
func (a *adapter) CredConfirm(uid t.Uid, method string) error {
// FIXME: There could be more than one credential of the same method.
res, err := a.db.Exec(
"UPDATE credentials SET updatedat=?,done=1,synthetic=CONCAT(method,':',value) WHERE userid=? AND method=?",
t.TimeNow(), store.DecodeUid(uid), method)
Expand All @@ -2206,15 +2217,18 @@ func (a *adapter) CredConfirm(uid t.Uid, method string) error {
return nil
}

// CredFail increments failure count of the given validation method.
func (a *adapter) CredFail(uid t.Uid, method string) error {
// FIXME: There could be more than one credential of the same method.
_, err := a.db.Exec("UPDATE credentials SET updatedat=?,retries=retries+1 WHERE userid=? AND method=?",
t.TimeNow(), store.DecodeUid(uid), method)
return err
}

// CredGet returns all credentials of the given user and method, validated or not.
func (a *adapter) CredGet(uid t.Uid, method string) ([]*t.Credential, error) {
query := "SELECT createdat,updatedat,method,value,resp,done,retries " +
"FROM credentials WHERE userid=?"
"FROM credentials WHERE userid=? ORDER BY createdat DESC"
args := []interface{}{store.DecodeUid(uid)}
if method != "" {
query += " AND method=?"
Expand Down Expand Up @@ -2347,7 +2361,7 @@ func (a *adapter) FileDeleteUnused(olderThan time.Time, limit int) ([]string, er
}

if len(ids) > 0 {
query, _, _ = sqlx.In("DELETE FROM fileuploads WHERE id IN (?)", ids)
query, ids, _ = sqlx.In("DELETE FROM fileuploads WHERE id IN (?)", ids)
_, err = tx.Exec(query, ids...)
if err != nil {
return nil, err
Expand Down

0 comments on commit 6c639a7

Please sign in to comment.