diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0bdfd49 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +keys diff --git a/README.md b/README.md new file mode 100644 index 0000000..fe80d31 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# decentralized-blogging-platform + +Decentralized blogging platform, using IPFS + + + +### Instructions + +- Need to add: +``` +ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["*"]' +``` +in order to allow access to IPFS from the app. + +- Start the IPFS daemon +``` +ipfs daemon +``` diff --git a/RESTfunctions.go b/RESTfunctions.go new file mode 100644 index 0000000..4a7e0b0 --- /dev/null +++ b/RESTfunctions.go @@ -0,0 +1,96 @@ +package main + +import ( + "encoding/json" + "fmt" + "net/http" + + "gopkg.in/mgo.v2/bson" +) + +type User struct { + Id bson.ObjectId `json:"id" bson:"_id,omitempty"` + Username string `json:"username"` + Email string `json:"email"` + Password string `json:"password"` + Token string `json:"token"` +} + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "clientApp") +} + +func Signup(w http.ResponseWriter, r *http.Request) { + decoder := json.NewDecoder(r.Body) + var user User + err := decoder.Decode(&user) + if err != nil { + panic(err) + } + defer r.Body.Close() + + fmt.Print("user signup: ") + fmt.Println(user.Username) + + //save the new project to mongodb + rUser := User{} + err = userCollection.Find(bson.M{"email": user.Email}).One(&rUser) + if err != nil { + //user not exists + err = userCollection.Insert(user) + err = userCollection.Find(bson.M{"email": user.Email}).One(&user) + } else { + //user exists + http.Error(w, "user already registered", http.StatusConflict) + return + } + + fmt.Println(user.Username) + jResp, err := json.Marshal(user) + if err != nil { + panic(err) + } + fmt.Fprintln(w, string(jResp)) +} + +func Login(w http.ResponseWriter, r *http.Request) { + + decoder := json.NewDecoder(r.Body) + var user User + err := decoder.Decode(&user) + if err != nil { + panic(err) + } + defer r.Body.Close() + //TODO check if the user password exists in the database + + fmt.Print("user login: ") + fmt.Println(user) + + //save the new project to mongodb + rUser := User{} + err = userCollection.Find(bson.M{"email": user.Email}).One(&rUser) + if err != nil { + http.Error(w, "error login, email not foun", http.StatusConflict) + return + } + //user exists, check password + if user.Password != rUser.Password { + http.Error(w, "error login, password not match", http.StatusConflict) + return + } + + token, err := newToken() + check(err) + rUser.Token = token + + //update with the token + err = userCollection.Update(bson.M{"_id": rUser.Id}, rUser) + check(err) + + jResp, err := json.Marshal(rUser) + if err != nil { + panic(err) + } + fmt.Fprintln(w, string(jResp)) +} diff --git a/config.json b/config.json new file mode 100755 index 0000000..d0f2924 --- /dev/null +++ b/config.json @@ -0,0 +1,8 @@ +{ + "apiport": "3000", + "webport": "8081", + "mongodb": { + "ip": "127.0.0.1:27017", + "database": "decentralized-blogging-platform" + } +} diff --git a/errors.go b/errors.go new file mode 100755 index 0000000..b3cf6b2 --- /dev/null +++ b/errors.go @@ -0,0 +1,15 @@ +package main + +import ( + "log" + "runtime" +) + +func check(err error) { + if err != nil { + _, fn, line, _ := runtime.Caller(1) + log.Println(line) + log.Println(fn) + log.Println(err) + } +} diff --git a/hash.go b/hash.go new file mode 100644 index 0000000..87c2932 --- /dev/null +++ b/hash.go @@ -0,0 +1,12 @@ +package main + +import ( + "crypto/sha256" + "encoding/base64" +) + +func hash(s string) string { + h := sha256.New() + h.Write([]byte(s)) + return base64.URLEncoding.EncodeToString(h.Sum(nil)) +} diff --git a/log.go b/log.go new file mode 100755 index 0000000..d12c469 --- /dev/null +++ b/log.go @@ -0,0 +1,19 @@ +package main + +import ( + "io" + "log" + "os" + "time" +) + +func savelog() { + timeS := time.Now().String() + _ = os.Mkdir("logs", os.ModePerm) + logFile, err := os.OpenFile("logs/log-"+timeS+".log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) + if err != nil { + panic(err) + } + mw := io.MultiWriter(os.Stdout, logFile) + log.SetOutput(mw) +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..ca1e809 --- /dev/null +++ b/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" + "log" + "net/http" + + "github.com/fatih/color" + "github.com/gorilla/handlers" + mgo "gopkg.in/mgo.v2" +) + +const keysDir = "keys" +const keysize = 2048 +const hashize = 1536 + +var userCollection *mgo.Collection + +func main() { + color.Blue("Starting ipfs-ai-models-market") + + readConfig("config.json") + fmt.Println(config) + + initializeToken() + + //mongodb + session, err := getSession() + check(err) + userCollection = getCollection(session, "users") + + //run thw webserver + go GUI() + + //run API + log.Println("api server running") + log.Print("port: ") + log.Println(config.APIPort) + router := NewRouter() + headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Access-Control-Allow-Origin"}) + originsOk := handlers.AllowedOrigins([]string{"*"}) + methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"}) + log.Fatal(http.ListenAndServe(":"+config.APIPort, handlers.CORS(originsOk, headersOk, methodsOk)(router))) +} + +func GUI() { + //here, run webserver + log.Println("webserver in port " + config.WebPort) + http.Handle("/", http.FileServer(http.Dir("./webapp"))) + http.ListenAndServe(":"+config.WebPort, nil) +} diff --git a/mongoOperations.go b/mongoOperations.go new file mode 100755 index 0000000..4b21ca6 --- /dev/null +++ b/mongoOperations.go @@ -0,0 +1,26 @@ +package main + +import ( + mgo "gopkg.in/mgo.v2" +) + +func getSession() (*mgo.Session, error) { + session, err := mgo.Dial("mongodb://" + config.Mongodb.IP) + if err != nil { + panic(err) + } + //defer session.Close() + + // Optional. Switch the session to a monotonic behavior. + session.SetMode(mgo.Monotonic, true) + + // Optional. Switch the session to a monotonic behavior. + session.SetMode(mgo.Monotonic, true) + + return session, err +} +func getCollection(session *mgo.Session, collection string) *mgo.Collection { + + c := session.DB(config.Mongodb.Database).C(collection) + return c +} diff --git a/readConfig.go b/readConfig.go new file mode 100755 index 0000000..3632cfb --- /dev/null +++ b/readConfig.go @@ -0,0 +1,26 @@ +package main + +import ( + "encoding/json" + "io/ioutil" +) + +//Config reads the config +type Config struct { + APIPort string `json:"apiport"` + WebPort string `json:"webport"` + Mongodb MongoConfig `json:"mongodb"` +} +type MongoConfig struct { + IP string `json:"ip"` + Database string `json:"database"` +} + +var config Config + +func readConfig(path string) { + file, err := ioutil.ReadFile(path) + check(err) + content := string(file) + json.Unmarshal([]byte(content), &config) +} diff --git a/restConfig.go b/restConfig.go new file mode 100755 index 0000000..36a332e --- /dev/null +++ b/restConfig.go @@ -0,0 +1,47 @@ +package main + +import ( + "log" + "net/http" + "time" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s\t%s\t%s\t%s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler + handler = route.HandlerFunc + handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + } + return router +} diff --git a/restRoutes.go b/restRoutes.go new file mode 100755 index 0000000..e053e94 --- /dev/null +++ b/restRoutes.go @@ -0,0 +1,24 @@ +package main + +type Routes []Route + +var routes = Routes{ + Route{ + "Index", + "GET", + "/", + Index, + }, + Route{ + "Signup", + "POST", + "/signup", + Signup, + }, + Route{ + "Login", + "POST", + "/login", + Login, + }, +} diff --git a/tokens.go b/tokens.go new file mode 100644 index 0000000..94db69c --- /dev/null +++ b/tokens.go @@ -0,0 +1,49 @@ +package main + +import ( + "fmt" + "time" + + jwt "github.com/dgrijalva/jwt-go" +) + +const ( + signingKey = "this is the secret signing key" +) + +var createdToken string + +func initializeToken() { + var err error + createdToken, err = newToken() + if err != nil { + fmt.Println("Creating token failed") + } +} + +func newToken() (string, error) { + signingKeyB := []byte(signingKey) + // Create the token + token := jwt.New(jwt.SigningMethodHS256) + // Set some claims + claims := make(jwt.MapClaims) + claims["foo"] = "bar" + claims["exp"] = time.Now().Add(time.Hour * 72).Unix() + token.Claims = claims + + // Sign and get the complete encoded token as a string + tokenString, err := token.SignedString(signingKeyB) + return tokenString, err +} + +func parseToken(myToken string, myKey string) { + token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) { + return []byte(myKey), nil + }) + + if err == nil && token.Valid { + fmt.Println("Your token is valid. I like your style.") + } else { + fmt.Println("This token is terrible! I cannot accept this.") + } +} diff --git a/webapp/.gitignore b/webapp/.gitignore new file mode 100644 index 0000000..19124e1 --- /dev/null +++ b/webapp/.gitignore @@ -0,0 +1,5 @@ +bower_components +node_modules +package-lock.json +keys +*.pem diff --git a/webapp/app.js b/webapp/app.js new file mode 100644 index 0000000..56016b0 --- /dev/null +++ b/webapp/app.js @@ -0,0 +1,88 @@ +'use strict'; + +var apiurl = "http://127.0.0.1:3000/"; + +angular.module('app', [ + 'ngRoute', + 'ngMessages', + 'toastr', + 'chart.js', + 'app.navbar', + 'app.signup', + 'app.login', + 'app.main', + 'app.newmodel', + 'app.profile' +]). +config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) { + $locationProvider.hashPrefix('!'); + /*$routeProvider.otherwise({ + redirectTo: '/main' + });*/ + + if((localStorage.getItem('dblog_user'))) + { + console.log(window.location.hash); + if((window.location.hash==='#!/login')||(window.location.hash==='#!/signup')) + { + window.location='#!/main'; + } + + $routeProvider.otherwise({redirectTo: '/main'}); + }else{ + if((window.location!=='#!/login')||(window.location!=='#!/signup')||(window.location!=='#!/main')) + { + console.log('app, user no logged'); + + localStorage.removeItem('dblog_user'); + localStorage.removeItem('dblog_user'); + window.location='#!/main'; + $routeProvider.otherwise({redirectTo: '/main'}); + } + } + }]) + .config(function(toastrConfig) { + angular.extend(toastrConfig, { + autoDismiss: false, + containerId: 'toast-container', + maxOpened: 0, + newestOnTop: true, + positionClass: 'toast-bottom-right', + preventDuplicates: false, + preventOpenDuplicates: false, + target: 'body' + }); + }) + .factory('httpInterceptor', function httpInterceptor() { + return { + request: function(config) { + return config; + }, + + requestError: function(config) { + return config; + }, + + response: function(res) { + return res; + }, + + responseError: function(res) { + return res; + } + }; + }) + .factory('api', function($http) { + return { + init: function() { + var dblog_user = JSON.parse(localStorage.getItem('dblog_user')); + if (dblog_user) { + $http.defaults.headers.common['Authorization'] = dblog_user.token; + $http.defaults.headers.post['Authorization'] = dblog_user.token; + } + } + }; + }) + .run(function(api) { + api.init(); + }); diff --git a/webapp/bower.json b/webapp/bower.json new file mode 100644 index 0000000..a5d1411 --- /dev/null +++ b/webapp/bower.json @@ -0,0 +1,19 @@ +{ + "name": "ipfs-ai-models-market", + "description": "", + "version": "0.0.0", + "homepage": "", + "license": "GNU", + "private": true, + "dependencies": { + "angular": "^1.6.2", + "angular-route": "^1.6.1", + "angular-messages": "^1.6.5", + "angular-bootstrap-material": "abm#^0.1.4", + "angular-bootstrap": "^2.5.0", + "components-font-awesome": "^4.7.0", + "angular-toastr": "^2.1.1", + "cssMaterialColors": "*", + "angular-chart.js": "^1.1.1" + } +} diff --git a/webapp/css/own.css b/webapp/css/own.css new file mode 100644 index 0000000..e3b46ad --- /dev/null +++ b/webapp/css/own.css @@ -0,0 +1,5 @@ +.o_nav { + background: #ffffff!important; + color: #000000!important; + /*border-bottom: 2px solid #4DD0E1!important;*/ +} diff --git a/webapp/img/icon.png b/webapp/img/icon.png new file mode 100644 index 0000000..0678b5b Binary files /dev/null and b/webapp/img/icon.png differ diff --git a/webapp/index.html b/webapp/index.html new file mode 100644 index 0000000..ed820ff --- /dev/null +++ b/webapp/index.html @@ -0,0 +1,73 @@ + + + +
+ +Some quick example text to build on the card title and make up the bulk of the card's content.
+ Go somewhere +# | +Title | +Description | +Accuracy | +Rating | +
---|---|---|---|---|
1 | +{{model.title}} | +{{model.description}} | +{{model.accuracy}} | +{{model.rating}} | +