Example #1
0
        public async Task <ActionResult <Thread> > CreatePost([FromBody] Thread newpost)
        {
            newpost.Id = 0;

            if (string.IsNullOrEmpty(newpost.Text))
            {
                return(BadRequest("Text body is too short"));
            }

            if (newpost.IsCommentReply && newpost.ParentId == -1)
            {
                return(BadRequest("Expected a comment, got a parent"));
            }

            if (string.IsNullOrEmpty(newpost.Username))
            {
                newpost.Username = "******";
            }

            var passw  = newpost.GeneratePassword;
            int passid = -1;

            if (!string.IsNullOrWhiteSpace(passw))
            {
                (var hash, var salt) = Passworder.GenerateHash(passw, this.Config.SiteConfig.DefaultPassword);
                var newpass = new Password()
                {
                    Hash = hash,
                    Salt = salt
                };
                this.Database.Passwords.Add(newpass);
                this.Database.SaveChanges();
                passid = newpass.Id;
            }

            newpost.GeneratePassword = "";
            newpost.PasswordId       = passid;

            await this.Database.Threads.AddAsync(newpost);

            await this.Database.SaveChangesAsync();

            //Run in background
            await Task.Run(async() => await Webhooker.SendContentToAllAsync(this.Database, newpost));

            return(newpost);
        }
Example #2
0
        public ActionResult <bool> DeletePost([FromQuery] int postid = -1, [FromQuery] string pass = "")
        {
            var thread = this.Database.Threads.FirstOrDefault(x => x.Id == postid);

            if (thread != null)
            {
                var passwd = this.Database.Passwords.FirstOrDefault(x => x.Id == thread.PasswordId);
                if (passwd != null)
                {
                    var passcorrect = Passworder.VerifyPassword(pass, passwd.Hash, passwd.Salt, this.Config.SiteConfig.DefaultPassword);
                    if (passcorrect)
                    {
                        this.Database.Threads.Remove(thread);
                        this.Database.SaveChanges();
                        return(Ok());
                    }
                }

                // failed, trying with master password
                var mpasswd      = this.Database.Passwords.First(x => x.Id == -1);
                var mpasscorrect = Passworder.VerifyPassword(pass, mpasswd.Hash, mpasswd.Salt, this.Config.SiteConfig.DefaultPassword);

                if (mpasscorrect)
                {
                    this.Database.Threads.Remove(thread);
                    this.Database.SaveChanges();
                    return(Ok());
                }

                return(BadRequest($"Received wrong password: {pass}"));
            }
            else
            {
                return(NotFound($"Thread with the ID '{postid}' was not found"));
            }
        }
Example #3
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            #region AspNetCoreRateLimit Stuff
            //Taken from https://github.com/stefanprodan/AspNetCoreRateLimit/wiki/IpRateLimitMiddleware#setup
            services.AddOptions();
            services.AddMemoryCache();

            services.Configure <IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
            services.Configure <IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));

            services.AddSingleton <IIpPolicyStore, MemoryCacheIpPolicyStore>();
            services.AddSingleton <IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();

            services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton <IRateLimitConfiguration, RateLimitConfiguration>();
            #endregion

            #region General Chandler Stuff

            services.AddSwaggerGen(x =>
            {
                x.SwaggerDoc("v1", new OpenApiInfo()
                {
                    Title   = "CHANdler API Documentation",
                    Version = "v1",
                    License = new OpenApiLicense()
                    {
                        Name = "GNU General Public License v3.0",
                        Url  = new Uri("https://github.com/Naamloos/CHANdler/blob/master/LICENSE")
                    },
                });

                x.IncludeXmlComments($"{AppContext.BaseDirectory}/{Assembly.GetExecutingAssembly().GetName().Name}.xml");
            });

            services.AddSingleton(_db);
            services.AddSingleton(_meta);
            services.AddSingleton(_config);
            services.AddCors(o => o.AddPolicy("publicpolicy", builder =>
            {
                builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader();
            }));

            this._db.Database.EnsureCreated();

            if (this._db.Boards.Count() == 0)
            {
                // insert debug thread data to database
                this._db.Boards.Add(new Board()
                {
                    Name        = "CHANdler",
                    Tag         = "c",
                    Description = "CHANdler test board",
                    ImageUrl    = "/res/logo.jpg"
                });

                this._db.Boards.Add(new Board()
                {
                    Name        = "Random",
                    Tag         = "r",
                    Description = "Random shit",
                });

                this._db.Boards.Add(new Board()
                {
                    Name        = "Memes",
                    Tag         = "m",
                    ImageUrl    = "/res/pepo.gif",
                    Description = "haha cool and good dank memes",
                });

                this._db.Boards.Add(new Board()
                {
                    Name        = "Meta",
                    Tag         = "meta",
                    ImageUrl    = "/res/wrench.png",
                    Description = "About CHANdler itself, e.g. development talk.",
                });

                (var hash, var salt) = Passworder.GenerateHash(this._config.SiteConfig.DefaultPassword, this._config.SiteConfig.DefaultPassword);

                this._db.Passwords.Add(new Password()
                {
                    Id   = -1,
                    Hash = hash,
                    Salt = salt
                });

                this._db.SaveChanges();
            }

            #region Auth and Forgery

            services.AddIdentity <ChandlerUser, IdentityRole>(x =>
            {
                x.Password.RequiredLength         = 8;
                x.Password.RequiredUniqueChars    = 0;
                x.Password.RequireDigit           = false;
                x.Password.RequireLowercase       = false;
                x.Password.RequireNonAlphanumeric = false;
                x.Password.RequireUppercase       = false;

                x.User.RequireUniqueEmail = true;

                x.Lockout.AllowedForNewUsers      = true;
                x.Lockout.DefaultLockoutTimeSpan  = TimeSpan.FromMinutes(15);
                x.Lockout.MaxFailedAccessAttempts = 5;

                x.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@_-+=?/!\\ ";
            }).AddEntityFrameworkStores <Database>()
            .AddDefaultTokenProviders()
            .AddUserManager <UserManager <ChandlerUser> >()
            .AddSignInManager <SignInManager <ChandlerUser> >();

            if (this._config.DiscordOAuthSettings != null)
            {
                var clientid     = this._config.DiscordOAuthSettings.ClientId.ToString();
                var clientsecret = this._config.DiscordOAuthSettings.ClientSecret;
                using var crng = new RNGCryptoServiceProvider();
                var arr = new byte[15];
                crng.GetBytes(arr);
                var nonce = Convert.ToBase64String(arr);

                services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddDiscord(x =>
                {
                    x.SignInScheme            = "Identity.External";
                    x.ClaimsIssuer            = DiscordAuthenticationDefaults.Issuer;
                    x.ReturnUrlParameter      = "/";
                    x.AccessDeniedPath        = "/";
                    x.ClientId                = clientid;
                    x.ClientSecret            = clientsecret;
                    x.TokenEndpoint           = DiscordAuthenticationDefaults.TokenEndpoint;
                    x.AuthorizationEndpoint   = $"{DiscordAuthenticationDefaults.AuthorizationEndpoint}?response_type=code&client_id={clientid}&scope=identify&state={nonce}&redirect_uri={this._config.DiscordOAuthSettings.RedirectUri}";
                    x.UserInformationEndpoint = DiscordAuthenticationDefaults.UserInformationEndpoint;
                });
            }
            else
            {
                services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
            }

            services.ConfigureApplicationCookie(x =>
            {
                x.LoginPath         = "/login";
                x.LogoutPath        = "/logout";
                x.AccessDeniedPath  = "/";
                x.ExpireTimeSpan    = TimeSpan.FromDays(1);
                x.SlidingExpiration = true;
            });

            services.AddAntiforgery(x =>
            {
                x.FormFieldName = "AntiForgeryToken";
                x.HeaderName    = "X-CRSF-TOKEN";
            });

            #endregion

            services.AddMvc(x => x.EnableEndpointRouting = false)
            .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
            .AddControllersAsServices();

            services.AddTransient <AccountHelper>();

            services.AddSingleton(new DbActionHelper(this._db));
            #endregion
        }