From 47bb4d0025eabb54da24060d63af4e9ccdbc4094 Mon Sep 17 00:00:00 2001 From: Mikkel Krautz Date: Fri, 8 Apr 2011 17:26:52 +0200 Subject: [PATCH] User support in MurmurDB import and freezer. --- Makefile | 1 + freeze.go | 77 ++++++++++++++++++++++++++++++++++----- grumble.go | 11 +++--- murmurdb.go | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++ server.go | 9 +++++ user.go | 39 ++++++++++++++++++++ 6 files changed, 223 insertions(+), 16 deletions(-) create mode 100644 user.go diff --git a/Makefile b/Makefile index 3c946ab..b384813 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,7 @@ GOFILES = \ channel.go \ acl.go \ group.go \ + user.go \ murmurdb.go \ freeze.go diff --git a/freeze.go b/freeze.go index 7fa645c..12f01a0 100644 --- a/freeze.go +++ b/freeze.go @@ -1,3 +1,7 @@ +// Copyright (c) 2011 The Grumble Authors +// The use of this source code is goverened by a BSD-style +// license that can be found in the LICENSE-file. + package main import ( @@ -7,9 +11,22 @@ import ( ) type frozenServer struct { - Id int "id" - MaxUsers int "max_user" - Channels []frozenChannel "channels" + Id int "id" + MaxUsers int "max_user" + SuperUserPassword string "super_user_password" + Channels []frozenChannel "channels" + Users []frozenUser "users" +} + +type frozenUser struct { + Id uint32 "id" + Name string "name" + CertHash string "cert_hash" + Email string "email" + TextureBlob string "texture_blob" + CommentBlob string "comment_blob" + LastChannelId int "last_channel_id" + LastActive uint64 "last_active" } type frozenChannel struct { @@ -21,8 +38,7 @@ type frozenChannel struct { Links []int "links" ACL []frozenACL "acl" Groups []frozenGroup "groups" - Description string "description" - DescriptionHash []byte "description_hash" + DescriptionBlob string "description_blob" } type frozenACL struct { @@ -45,6 +61,7 @@ type frozenGroup struct { // Freeze a server func (server *Server) Freeze() (fs frozenServer, err os.Error) { fs.Id = int(server.Id) + fs.SuperUserPassword = server.superUserPassword fs.MaxUsers = server.MaxUsers channels := []frozenChannel{} @@ -57,6 +74,16 @@ func (server *Server) Freeze() (fs frozenServer, err os.Error) { } fs.Channels = channels + users := []frozenUser{} + for _, u := range server.Users { + fu, err := u.Freeze() + if err != nil { + return + } + users = append(users, fu) + } + fs.Users = users + return } @@ -71,8 +98,6 @@ func (channel *Channel) Freeze() (fc frozenChannel, err os.Error) { } fc.Position = int64(channel.Position) fc.InheritACL = channel.InheritACL - fc.Description = channel.Description - fc.DescriptionHash = channel.DescriptionHash acls := []frozenACL{} for _, acl := range channel.ACL { @@ -103,6 +128,20 @@ func (channel *Channel) Freeze() (fc frozenChannel, err os.Error) { return } +// Freeze a User +func (user *User) Freeze() (fu frozenUser, err os.Error) { + fu.Id = user.Id + fu.Name = user.Name + fu.CertHash = user.CertHash + fu.Email = user.Email + fu.TextureBlob = user.TextureBlob + fu.CommentBlob = user.CommentBlob + fu.LastChannelId = user.LastChannelId + fu.LastActive = user.LastActive + + return +} + // Freeze a ChannelACL func (acl *ChannelACL) Freeze() (facl frozenACL, err os.Error) { facl.UserId = acl.UserId @@ -148,14 +187,15 @@ func NewServerFromFrozen(filename string) (s *Server, err os.Error) { return nil, err } + s.superUserPassword = fs.SuperUserPassword + // Add all channels, but don't hook up parent/child relationships // until all of them are loaded. for _, jc := range fs.Channels { c := NewChannel(jc.Id, jc.Name) c.Position = int(jc.Position) c.InheritACL = jc.InheritACL - c.Description = jc.Description - c.DescriptionHash = jc.DescriptionHash + c.DescriptionHash = []byte{} // fixme for _, jacl := range jc.ACL { acl := NewChannelACL(c) @@ -201,5 +241,24 @@ func NewServerFromFrozen(filename string) (s *Server, err os.Error) { s.root = s.Channels[0] + // Add all users + for _, ju := range fs.Users { + u, err := NewUser(ju.Id, ju.Name) + if err != nil { + return nil, err + } + + u.CertHash = ju.CertHash + u.Email = ju.Email + u.TextureBlob = ju.TextureBlob + u.CommentBlob = ju.CommentBlob + u.LastChannelId = ju.LastChannelId + u.LastActive = ju.LastActive + + s.Users[u.Id] = u + s.UserNameMap[u.Name] = u + s.UserCertMap[u.CertHash] = u + } + return s, nil } diff --git a/grumble.go b/grumble.go index ece3afe..ead227c 100644 --- a/grumble.go +++ b/grumble.go @@ -51,28 +51,25 @@ func MurmurImport(filename string) (err os.Error) { for _, sid := range servers { m, err := NewServerFromSQLite(sid, db) if err != nil { - log.Printf("Unable to create server: %s", err.String()) - return + return err } f, err := os.Create(filepath.Join(*datadir, fmt.Sprintf("%v", sid))) if err != nil { - log.Printf("%s", err.String()) - return + return err } zf, err := gzip.NewWriterLevel(f, gzip.BestCompression) fz, err := m.Freeze() if err != nil { - log.Fatalf("Unable to freeze server: %s", err.String()) + return err } enc := gob.NewEncoder(zf) err = enc.Encode(fz) if err != nil { - log.Printf("%s", err.String()) - return + return err } zf.Close() diff --git a/murmurdb.go b/murmurdb.go index 5ac991d..c0e58f8 100644 --- a/murmurdb.go +++ b/murmurdb.go @@ -1,3 +1,7 @@ +// Copyright (c) 2011 The Grumble Authors +// The use of this source code is goverened by a BSD-style +// license that can be found in the LICENSE-file. + package main // This file implements a Server that can be created from a Murmur SQLite file. @@ -42,6 +46,11 @@ func NewServerFromSQLite(id int64, db *sqlite.Conn) (s *Server, err os.Error) { return nil, err } + err = populateUsers(s, db) + if err != nil { + return nil, err + } + return } @@ -268,3 +277,96 @@ func populateChannelLinkInfo(server *Server, db *sqlite.Conn) (err os.Error) { return nil } + +func populateUsers(server *Server, db *sqlite.Conn) (err os.Error) { + // Populate the server with regular user data + stmt, err := db.Prepare("SELECT user_id, name, pw, lastchannel, texture, strftime('%s', last_active) FROM users WHERE server_id=?") + if err != nil { + return + } + + err = stmt.Exec(server.Id) + if err != nil { + return + } + + for stmt.Next() { + var ( + UserId int64 + UserName string + SHA1Password string + LastChannel int + Texture []byte + LastActive int64 + ) + + err = stmt.Scan(&UserId, &UserName, &SHA1Password, &LastChannel, &Texture, &LastActive) + if err != nil { + continue + } + + if UserId == 0 { + server.superUserPassword = "sha1" + SHA1Password + continue + } + + user, err := NewUser(uint32(UserId), UserName) + if err != nil { + return err + } + + user.LastActive = uint64(LastActive) + user.LastChannelId = LastChannel + + server.Users[user.Id] = user + } + + stmt, err = db.Prepare("SELECT key, value FROM user_info WHERE server_id=? AND user_id=?") + if err != nil { + return + } + + // Populate users with any new-style UserInfo records + for uid, user := range server.Users { + err = stmt.Reset() + if err != nil { + return err + } + + err = stmt.Exec(server.Id, uid) + if err != nil { + return err + } + + for stmt.Next() { + var ( + Key int + Value string + ) + + err = stmt.Scan(&Key, &Value) + if err != nil { + return err + } + + switch Key { + case UserInfoEmail: + user.Email = Value + case UserInfoComment: + // unhandled + case UserInfoHash: + user.CertHash = "sha1-" + Value + case UserInfoLastActive: + // not a kv-pair (trigger) + case UserInfoPassword: + // not a kv-pair + case UserInfoName: + // not a kv-pair + } + } + } + + + return +} + diff --git a/server.go b/server.go index 7470b1b..7323afc 100644 --- a/server.go +++ b/server.go @@ -68,6 +68,12 @@ type Server struct { root *Channel Channels map[int]*Channel + // Users + superUserPassword string + Users map[uint32]*User + UserCertMap map[string]*User + UserNameMap map[string]*User + // ACL cache aclcache ACLCache } @@ -81,6 +87,9 @@ func NewServer(id int64, addr string, port int) (s *Server, err os.Error) { s.port = port s.clients = make(map[uint32]*Client) + s.Users = make(map[uint32]*User) + s.UserCertMap = make(map[string]*User) + s.UserNameMap = make(map[string]*User) s.hclients = make(map[string][]*Client) s.hpclients = make(map[string]*Client) diff --git a/user.go b/user.go new file mode 100644 index 0000000..26828a3 --- /dev/null +++ b/user.go @@ -0,0 +1,39 @@ +// Copyright (c) 2011 The Grumble Authors +// The use of this source code is goverened by a BSD-style +// license that can be found in the LICENSE-file. + +package main + +import ( + "os" +) + +// This file implements Server's handling of Users. +// +// Users are registered clients on the server. + +type User struct { + Id uint32 + Name string + CertHash string + Email string + TextureBlob string + CommentBlob string + LastChannelId int + LastActive uint64 +} + +// Create a new User +func NewUser(id uint32, name string) (user *User, err os.Error) { + if id < 0 { + return nil, os.NewError("Invalid user id") + } + if len(name) == 0 || name == "SuperUser" { + return nil, os.NewError("Invalid username") + } + + return &User{ + Id: id, + Name: name, + }, nil +}