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 @@ + + + + + + ipfs-ai-models-market + + + + + + + + + + + + + + + + + + + +
+



+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webapp/package.json b/webapp/package.json new file mode 100644 index 0000000..061866f --- /dev/null +++ b/webapp/package.json @@ -0,0 +1,13 @@ +{ + "name": "decentralized-blogging-platform", + "version": "1.0.0", + "description": "", + "scripts": { + "postinstall": "bower install", + "prestart": "npm install", + "start": "http-server" + }, + "dependencies": { + "bootstrap": "^4.0.0" + } +} diff --git a/webapp/views/login/login.html b/webapp/views/login/login.html new file mode 100755 index 0000000..04e91f5 --- /dev/null +++ b/webapp/views/login/login.html @@ -0,0 +1,35 @@ +
+
+
+ +
+
+
+
+

+ Login +

+
+ +
+
+ +
+
+
+ Signup +
+
+
Login
+
+
+
+
+
+ + +
+ +
+
+
diff --git a/webapp/views/login/login.js b/webapp/views/login/login.js new file mode 100755 index 0000000..42d36f9 --- /dev/null +++ b/webapp/views/login/login.js @@ -0,0 +1,36 @@ +'use strict'; + +angular.module('app.login', ['ngRoute']) + + .config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/login', { + templateUrl: 'views/login/login.html', + controller: 'LoginCtrl' + }); + }]) + + .controller('LoginCtrl', function($scope, $rootScope, $http, $routeParams, toastr) { + $rootScope.server = "" + $scope.user = {}; + + $scope.login = function() { + $http({ + url: apiurl + 'login', + method: "POST", + headers: { + "Content-Type": undefined + }, + data: $scope.user + }) + .then(function(data) { + console.log("data: "); + console.log(data.data); + localStorage.setItem("dblog_user", JSON.stringify(data.data)); + window.location.reload(); + }, + function(data) { + console.log(data); + }); + + }; + }); diff --git a/webapp/views/main/main.html b/webapp/views/main/main.html new file mode 100755 index 0000000..3acdf08 --- /dev/null +++ b/webapp/views/main/main.html @@ -0,0 +1,14 @@ +
+
+
+
+ Card image cap +
+
Post1
+

Some quick example text to build on the card title and make up the bulk of the card's content.

+ Go somewhere +
+
+
+
+
diff --git a/webapp/views/main/main.js b/webapp/views/main/main.js new file mode 100755 index 0000000..fb833fc --- /dev/null +++ b/webapp/views/main/main.js @@ -0,0 +1,16 @@ +'use strict'; + +angular.module('app.main', ['ngRoute']) + + .config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/main', { + templateUrl: 'views/main/main.html', + controller: 'MainCtrl' + }); + }]) + + .controller('MainCtrl', function($scope, $rootScope, $http) { + + + + }); diff --git a/webapp/views/navbar.html b/webapp/views/navbar.html new file mode 100755 index 0000000..da1123a --- /dev/null +++ b/webapp/views/navbar.html @@ -0,0 +1,49 @@ +
+ +
diff --git a/webapp/views/navbar.js b/webapp/views/navbar.js new file mode 100755 index 0000000..706c3ea --- /dev/null +++ b/webapp/views/navbar.js @@ -0,0 +1,20 @@ +'use strict'; + +angular.module('app.navbar', ['ngRoute']) + + .config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/navbar', { + templateUrl: 'views/navbar.html', + controller: 'NavbarCtrl' + }); + }]) + + .controller('NavbarCtrl', function($scope) { + $scope.user = JSON.parse(localStorage.getItem("dblog_user")); + console.log("user", $scope.user); + $scope.logout = function() { + localStorage.removeItem("dblog_user"); + window.location.reload(); + }; + + }); diff --git a/webapp/views/navbarOLD.html b/webapp/views/navbarOLD.html new file mode 100644 index 0000000..d363130 --- /dev/null +++ b/webapp/views/navbarOLD.html @@ -0,0 +1,51 @@ +
+ +
diff --git a/webapp/views/newmodel/newmodel.html b/webapp/views/newmodel/newmodel.html new file mode 100644 index 0000000..9d41474 --- /dev/null +++ b/webapp/views/newmodel/newmodel.html @@ -0,0 +1,18 @@ +
+
+
+
+
+

New model

+ + + + + + + Upload +
+
+
+
+
diff --git a/webapp/views/newmodel/newmodel.js b/webapp/views/newmodel/newmodel.js new file mode 100644 index 0000000..dd09e51 --- /dev/null +++ b/webapp/views/newmodel/newmodel.js @@ -0,0 +1,79 @@ +'use strict'; + +angular.module('app.newmodel', ['ngRoute']) + + .config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/newmodel', { + templateUrl: 'views/newmodel/newmodel.html', + controller: 'NewModelCtrl' + }); + }]) + + .controller('NewModelCtrl', function($scope, $rootScope, $http, toastr) { + + $scope.file = {}; + + $scope.upload = function() { + console.log("upload model"); + var formdata = new FormData(); + formdata.append("file", $scope.file); + + //add the file to ipfs + /*$http({ + url: ipfs_url + 'add', + method: "POST", + headers: { + "Content-Type": undefined + }, + data: formdata + }) + .then(function(data) { + console.log("data: "); + console.log(data.data); + toastr.success("Model added to IPFS"); + }, + function(data) { + console.log(data); + toastr.error("Error adding Model to IPFS"); + });*/ + + //add the data to userdata + $http({ + url: clienturl + 'model', + method: "POST", + headers: { + "Content-Type": undefined + }, + data: $scope.model + }) + .then(function(data) { + console.log("data: "); + console.log(data.data); + window.location="/"; + toastr.success("Model uploaded"); + }, + function(data) { + console.log(data); + }); + + + }; + + + + }) + .directive('fileModel', ['$parse', function($parse) { + //directive code from https://www.tutorialspoint.com/angularjs/angularjs_upload_file.htm + return { + restrict: 'A', + link: function(scope, element, attrs) { + var model = $parse(attrs.fileModel); + var modelSetter = model.assign; + element.bind('change', function() { + scope.$apply(function() { + modelSetter(scope, element[0].files[0]); + }); + }); + } + }; + }]); diff --git a/webapp/views/profile/profile.html b/webapp/views/profile/profile.html new file mode 100644 index 0000000..fd95768 --- /dev/null +++ b/webapp/views/profile/profile.html @@ -0,0 +1,31 @@ +
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + +
#TitleDescriptionAccuracyRating
1{{model.title}}{{model.description}}{{model.accuracy}}{{model.rating}}
+
+
+
+
diff --git a/webapp/views/profile/profile.js b/webapp/views/profile/profile.js new file mode 100644 index 0000000..08d681c --- /dev/null +++ b/webapp/views/profile/profile.js @@ -0,0 +1,24 @@ +'use strict'; + +angular.module('app.profile', ['ngRoute']) + + .config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/profile', { + templateUrl: 'views/profile/profile.html', + controller: 'ProfileCtrl' + }); + }]) + + .controller('ProfileCtrl', function($scope, $rootScope, $http) { + + $http.get(clienturl + 'user') + .then(function(data) { + console.log('data success'); + console.log(data); + $scope.user = data.data; + localStorage.setItem("ai_user", JSON.stringify($scope.user)); + + }, function(data) { + console.log('no user'); + }); + }); diff --git a/webapp/views/signup/signup.html b/webapp/views/signup/signup.html new file mode 100755 index 0000000..571f5fc --- /dev/null +++ b/webapp/views/signup/signup.html @@ -0,0 +1,38 @@ +
+
+
+ +
+
+
+
+

+ Signup +

+
+ +
+
+ +
+
+ +
+
+
+ Cancel +
+
+
Signup
+
+
+
+
+
+ + +
+ +
+
+
diff --git a/webapp/views/signup/signup.js b/webapp/views/signup/signup.js new file mode 100755 index 0000000..c37b1f7 --- /dev/null +++ b/webapp/views/signup/signup.js @@ -0,0 +1,34 @@ +'use strict'; + +angular.module('app.signup', ['ngRoute']) + +.config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/signup', { + templateUrl: 'views/signup/signup.html', + controller: 'SignupCtrl' + }); +}]) + +.controller('SignupCtrl', function($scope, $http, $routeParams, $rootScope) { + $scope.signup = function() { + console.log('Doing signup', $scope.user); + $http({ + url: apiurl + 'signup', + method: "POST", + headers: { + "Content-Type": undefined + }, + data: $scope.user + }) + .then(function(data) { + console.log("data: "); + console.log(data.data); + window.location="/#!/login"; + + }, + function(data) { + console.log(data); + }); + + }; +});