1 ///
2 /// User data, privileges, details and preferences implementation.
3 /// @file       user.h - pianod project
4 /// @author     Perette Barella
5 /// @date       Initial: 2012-03-20.  Split from users.c: 2014-11-20.
6 /// @copyright  Copyright 2012-2020 Devious Fish. All rights reserved.
7 ///
8 
9 #pragma once
10 
11 #include <config.h>
12 
13 #include <string>
14 #include <unordered_map>
15 
16 #include <parsnip.h>
17 
18 #include "logging.h"
19 #include "fundamentals.h"
20 #include "enumeratedarray.h"
21 #include "datastore.h"
22 
23 /// User types in ascending ranks/level of authority
24 enum class Rank {
25 	None,              ///< User is unauthorized to do anything except log in.
26 	Listener,          ///< User can query and view song-related data, but not change selections.
27 	Standard,          ///< User can query, choose playlist, request music, change volume.
28 	Administrator      ///< User has full authorization, except for accessing others' private data.
29 };
30 
31 /// User privilege flags, corresponding to an array position.
32 enum class Privilege {
33 	Service,      ///< User may add or remove sources.  (Automatic for admin rank.)
34     Queue,        ///< User may queue or cancel songs.  (Automatic for standard rank.)
35 	Influence,    ///< User's playlist preferences influence autotuning selections.
36 	Tuner,        ///< User may set other users' presence, for autotuning.
37     Shadow,       ///< Attribute: User was created automatically, shadowing a user account.
38 	Present,      ///< Attribute: Consider user present, even if not logged in.
39 	Count
40 };
41 
42 /// Postfix increment operator to allow Privilege iteration.
43 static inline Privilege operator++(Privilege &p, int) {
44     Privilege prior = p;
45     p = static_cast<Privilege>(int (prior) + 1);
46     return prior;
47 }
48 
49 
50 class PianodService;
51 
52 /// Data about each user
53 class User {
54     friend class UserManager;
55     static bool shadow_mode;
56     static time_t write_time;
57 private:
58     typedef enum user_write_priority_t {
59         CRITICAL = 1, ///< User removal, privilege change, etc.
60         IMPORTANT = 10, ///< User creation
61         NOMINAL = 60, ///< Sources, preferences, data attachments, etc.
62         TRIVIAL = 300 ///< Ratings
63     } WritePriority;
64     std::string name; ///< User's login name
65     std::string password; ///< Encrypted password
66     Rank rank = Rank::None; ///< Assigned rank.
67     EnumeratedArray<Privilege, bool> privileges; ///< Assigned privileges.
68     // Note: effective privileges may be different, an effect of rank.
69 
70     using UserDataPair = std::pair <std::string, UserData::DataStore *>;
71     using UserDataMap = std::unordered_map <std::string, UserData::DataStore *>;
72     UserDataMap data; ///< Data sets attached to the user
73 
74     static void scheduleWrite (WritePriority priority);
75 public:
76     User (const std::string &username, const std::string &pass, bool encrypt = false);
77     User (const User &) = delete;
78     User &operator=(const User &) = delete;
79     User (User &&) = default;
80     User &operator=(User &&) = default;
81     ~User ();
username(void)82     inline const std::string &username (void) const { return name; };
83     void setPassword (const char *pass);
84     bool authenticate (const char *trypass) const;
authenticate(const std::string & trypass)85     bool authenticate (const std::string &trypass) const { return authenticate (trypass.c_str()); };
86     bool changePassword (const char *old, const char *pass);
87 #ifdef SHADOW_CAPABLE
88     bool assumeShadowPassword (const char *old, const char *pass);
89 #endif
90     // Rank stuff
91     void assignRank (Rank newrank);
92     bool assignRank (const char *newrank);
93     bool haveRank (const Rank rank) const;
getRank(void)94     inline Rank getRank (void) const { return rank; };
95     const char *getRankName (void) const;
96     // Privilege stuff
97     void setPrivilege (const Privilege priv, bool setting);
98     bool havePrivilege (const Privilege priv) const;
99     // Other statusy things
100     bool online (const PianodService &service) const;
101     bool attachData (UserData::DataStore *);
updateData(void)102     inline void updateData (void) { scheduleWrite (TRIVIAL); };
103     UserData::DataStore *getData (const std::string &datatype, const std::string &dataid = "") const;
104     void removeData (const std::string &datatype, const std::string &dataid = "");
105 protected:
106     inline bool operator < (const User &other) {
107         return name.compare (other.name);
108     }
109     inline bool operator < (const std::string &other) {
110         return name.compare (other);
111     }
112     Parsnip::SerialData persist () const;
113 
114     // Static methods & Variables
115 public:
116     static Rank visitor_rank; ///< Rank for users that have not authenticated.
117     static void shadow (bool mode);
shadow()118     static bool shadow () { return (shadow_mode); };
119     static const Privilege getPrivilege (const std::string &privilege);
120     static const Rank getRank (const std::string &rank);
121     static const char *getRankName (Rank rank);
122     static const char *getPrivilegeName (Privilege privilege);
getVisitorRank()123     static inline Rank getVisitorRank () {
124         return visitor_rank;
125     }
126     static bool setVisitorRank (const std::string &rank);
127     static User *getStartscriptUser (void);
128 private:
129     static bool reconstituteUserData (User &user, const Parsnip::SerialData &data);
130     static User reconstitute_user (const Parsnip::SerialData &data);
131 };
132 
133 class PianodConnection;
134 void send_privileges (PianodConnection &conn, const User *user);
135 
136 namespace Football {
137     class ServiceBase;
138 }
139 
140 extern void register_user_commands (Football::ServiceBase *service);
141 
142