├── .gitattributes
├── .github
├── FUNDING.yml
└── stale.yml
├── .gitignore
├── LICENSE.txt
├── README.md
└── src
└── Lithnet.Laps.Web
├── Lithnet.Laps.Web.sln
└── Lithnet.Laps.Web
├── App_Data
└── Templates
│ ├── EmailAuditFailure.html
│ ├── EmailAuditSuccess.html
│ ├── LogAuditFailure.txt
│ └── LogAuditSuccess.txt
├── App_LocalResources
├── LogMessages.Designer.cs
├── LogMessages.resx
├── UIMessages.Designer.cs
├── UIMessages.it.Designer.cs
├── UIMessages.it.resx
└── UIMessages.resx
├── App_Start
├── BundleConfig.cs
├── FilterConfig.cs
└── RouteConfig.cs
├── ConfigSection
├── AuditElement.cs
├── LapsConfigSection.cs
├── RateLimitIPElement.cs
├── RateLimitUserElement.cs
├── ReaderCollection.cs
├── ReaderElement.cs
├── TargetCollection.cs
├── TargetElement.cs
└── TargetType.cs
├── Content
├── Site.css
├── bootstrap-grid.css
├── bootstrap-grid.css.map
├── bootstrap-grid.min.css
├── bootstrap-grid.min.css.map
├── bootstrap-reboot.css
├── bootstrap-reboot.css.map
├── bootstrap-reboot.min.css
├── bootstrap-reboot.min.css.map
├── bootstrap.css
├── bootstrap.css.map
├── bootstrap.min.css
├── bootstrap.min.css.map
├── fontawesome
│ ├── fa-brands.css
│ ├── fa-brands.min.css
│ ├── fa-regular.css
│ ├── fa-regular.min.css
│ ├── fa-solid.css
│ ├── fa-solid.min.css
│ ├── fontawesome-all.css
│ ├── fontawesome-all.min.css
│ ├── fontawesome.css
│ └── fontawesome.min.css
└── webfonts
│ ├── Inconsolata-Regular.ttf
│ ├── fa-brands-400.eot
│ ├── fa-brands-400.svg
│ ├── fa-brands-400.ttf
│ ├── fa-brands-400.woff
│ ├── fa-brands-400.woff2
│ ├── fa-regular-400.eot
│ ├── fa-regular-400.svg
│ ├── fa-regular-400.ttf
│ ├── fa-regular-400.woff
│ ├── fa-regular-400.woff2
│ ├── fa-solid-900.eot
│ ├── fa-solid-900.svg
│ ├── fa-solid-900.ttf
│ ├── fa-solid-900.woff
│ └── fa-solid-900.woff2
├── Controllers
├── HomeController.cs
└── LapController.cs
├── Exceptions
└── NoMatchingTargetException.cs
├── Global.asax
├── Global.asax.cs
├── Internal
├── Directory.cs
├── EventIDs.cs
├── Extensions.cs
├── RateLimiter.cs
└── Reporting.cs
├── Lithnet.Laps.Web.csproj
├── Lithnet.Laps.Web.csproj.DotSettings
├── Models
├── LapEntryModel.cs
└── LapRequestModel.cs
├── Properties
├── AssemblyInfo.cs
└── PublishProfiles
│ ├── FolderProfile.pubxml
│ └── Publish to local IIS.pubxml
├── Scripts
├── README.md
├── bootstrap.bundle.js
├── bootstrap.bundle.js.map
├── bootstrap.bundle.min.js
├── bootstrap.bundle.min.js.map
├── bootstrap.js
├── bootstrap.js.map
├── bootstrap.min.js
├── bootstrap.min.js.map
├── clipboard.min.js
├── esm
│ ├── popper-utils.js
│ ├── popper-utils.js.map
│ ├── popper-utils.min.js
│ ├── popper-utils.min.js.map
│ ├── popper.js
│ ├── popper.js.map
│ ├── popper.min.js
│ └── popper.min.js.map
├── index.d.ts
├── init-clip.js
├── jquery-3.3.1.intellisense.js
├── jquery-3.3.1.js
├── jquery-3.3.1.min.js
├── jquery-3.3.1.min.map
├── jquery-3.3.1.slim.js
├── jquery-3.3.1.slim.min.js
├── jquery-3.3.1.slim.min.map
├── jquery.validate-vsdoc.js
├── jquery.validate.js
├── jquery.validate.min.js
├── jquery.validate.unobtrusive.js
├── jquery.validate.unobtrusive.min.js
├── popper-utils.js
├── popper-utils.js.map
├── popper-utils.min.js
├── popper-utils.min.js.map
├── popper.js
├── popper.js.map
├── popper.min.js
├── popper.min.js.map
└── umd
│ ├── popper-utils.js
│ ├── popper-utils.js.map
│ ├── popper-utils.min.js
│ ├── popper-utils.min.js.map
│ ├── popper.js
│ ├── popper.js.map
│ ├── popper.min.js
│ └── popper.min.js.map
├── Startup.cs
├── Views
├── Home
│ ├── AuthNError.cshtml
│ ├── Index.cshtml
│ └── LogOut.cshtml
├── Lap
│ ├── Get.cshtml
│ ├── RateLimitExceeded.cshtml
│ └── Show.cshtml
├── Shared
│ ├── Error.cshtml
│ └── _Layout.cshtml
├── Web.config
└── _ViewStart.cshtml
├── Web.Debug.config
├── Web.Release.config
├── Web.config
├── clipboard.min.js
├── favicon.ico
├── images
└── logo.png
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 | custom: ['https://lithnet.io/donate']
3 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Number of days of inactivity before an issue becomes stale
2 | daysUntilStale: 60
3 | # Number of days of inactivity before a stale issue is closed
4 | daysUntilClose: 7
5 | # Issues with these labels will never be considered stale
6 | exemptLabels:
7 | - pinned
8 | - security
9 | # Label to use when marking an issue as stale
10 | staleLabel: stale
11 | # Comment to post when marking an issue as stale. Set to `false` to disable
12 | markComment: >
13 | This issue has been automatically marked as stale because it has not had
14 | recent activity. It will be closed in 7 days if no further activity occurs.
15 | # Comment to post when closing a stale issue. Set to `false` to disable
16 | closeComment: false
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | *.nupkg
156 | # The packages folder can be ignored because of Package Restore
157 | **/packages/*
158 | # except build/, which is used as an MSBuild target.
159 | !**/packages/build/
160 | # Uncomment if necessary however generally it will be regenerated when needed
161 | #!**/packages/repositories.config
162 | # NuGet v3's project.json files produces more ignoreable files
163 | *.nuget.props
164 | *.nuget.targets
165 |
166 | # Microsoft Azure Build Output
167 | csx/
168 | *.build.csdef
169 |
170 | # Microsoft Azure Emulator
171 | ecf/
172 | rcf/
173 |
174 | # Windows Store app package directories and files
175 | AppPackages/
176 | BundleArtifacts/
177 | Package.StoreAssociation.xml
178 | _pkginfo.txt
179 |
180 | # Visual Studio cache files
181 | # files ending in .cache can be ignored
182 | *.[Cc]ache
183 | # but keep track of directories ending in .cache
184 | !*.[Cc]ache/
185 |
186 | # Others
187 | ClientBin/
188 | ~$*
189 | *~
190 | *.dbmdl
191 | *.dbproj.schemaview
192 | *.jfm
193 | *.pfx
194 | *.publishsettings
195 | node_modules/
196 | orleans.codegen.cs
197 |
198 | # Since there are multiple workflows, uncomment next line to ignore bower_components
199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200 | #bower_components/
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # GhostDoc plugin setting file
226 | *.GhostDoc.xml
227 |
228 | # Node.js Tools for Visual Studio
229 | .ntvs_analysis.dat
230 |
231 | # Visual Studio 6 build log
232 | *.plg
233 |
234 | # Visual Studio 6 workspace options file
235 | *.opt
236 |
237 | # Visual Studio LightSwitch build output
238 | **/*.HTMLClient/GeneratedArtifacts
239 | **/*.DesktopClient/GeneratedArtifacts
240 | **/*.DesktopClient/ModelManifest.xml
241 | **/*.Server/GeneratedArtifacts
242 | **/*.Server/ModelManifest.xml
243 | _Pvt_Extensions
244 |
245 | # Paket dependency manager
246 | .paket/paket.exe
247 | paket-files/
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | # JetBrains Rider
253 | .idea/
254 | *.sln.iml
255 |
256 | # CodeRush
257 | .cr/
258 |
259 | # Python Tools for Visual Studio (PTVS)
260 | __pycache__/
261 | *.pyc
262 |
263 | secrets.config
264 | *.dev.config
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Lithnet
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | # Lithnet LAPS Web App is now Lithnet Access Manager!
3 | [Lithnet Access Manager](https://lithnet.io/products/access-manager) (AMS) is the next generation of Lithnet LAPS web. Lithnet Access Manager provides all the functionality of LAPS web, and more! This guide will explain the key differences between the products, and how to get started on your upgrade journey.
4 |
5 | ### User experience
6 | LAPS web users will feel a sense of familiarity with the Access Manager interface - while we have freshened-up the user interface, the experience is kept similar to LAPS web to minimize the organization change impact of upgrading to AMS.
7 | We've added features like showing a phonetic breakdown of the password (great for reading passwords out over the phone) and reading the password aloud using the text-to-speech engine of the browser.
8 |
9 | Our products have been first and foremost designed to enhance the experience of support staff in the field, and that experience continues with AMS.
10 |
11 | ### Administration and configuration experience
12 | We've ditched the need for IIS completely, so AMS runs as a standalone service. Along with a single installer executable, this drastically reduces the complexity of the setup and upgrade process.
13 |
14 | One of the biggest benefits to LAPS web administrators is that the dreaded config file has now been replaced with an intuitive configuration user interface. All configuration is now done through the configuration tool.
15 |
16 | Instead of fighting with XML, you're now able to use the familiar built-in security editor to assign permissions.
17 |
18 | We've rebuilt the authorization engine to solve common complaints about LAPS web, such as the computer not being able to be part of multiple targets, or errors that occur when organizational units used in targets are removed from the directory.
19 |
20 | You'll find support for new things like smart card authentication, sending audit notifications to Slack and Microsoft Teams, and scripts automatically generated by the application to help you configure things like permission delegation in AD.
21 |
22 | We know you'll just love the new features and configuration experience!
23 |
24 | ### Licensing
25 | Access Manager comes in two editions - Standard and Enterprise edition. Standard edition is free for all organizations, while enterprise edition is a paid product.
26 |
27 | However, **all scenarios supported by LAPS web, continue to be free in the Standard Edition of Access Manager**. LAPS web users can upgrade to AMS Standard edition, without any loss of functionality. In fact, the standard edition of AMS brings many new features that were not available in LAPS web, including support for accessing BitLocker recovery keys, and providing just-in-time administrative access to Windows computers.
28 |
29 | Enterprise edition offers features that were never available in LAPS web, and includes a dedicated support offering.
30 |
31 | See our [comparison guide](https://lithnet.io/ams-features) for more information on the differences between the standard and enterprise edition offerings.
32 |
33 | ### Migration
34 | Ready to get started?
35 |
36 | 1. First, download the latest edition of Access Manager from the [downloads](https://lithnet.io/products/access-manager/downloads) page.
37 | 2. We recommend starting with a new server to install AMS on. Otherwise, you may run into contention over the use of the web server ports between LAPS web and IIS and the new product.
38 | 3. [Install and configure the Access Manager Service](https://docs.lithnet.io/ams/installation/getting-started). You'll need to re-setup some things like the authentication provider, email setup, and UI options.
39 | 4. Finally, you can automatically import all your authorization rules directly from your LAPS web config file, using the [import wizard](https://docs.lithnet.io/ams/configuration/importing/importing-rules-from-lithnet-laps-web-app)
40 |
41 | If you run into any issues, you can log an [issue here on GitHub](https://github.com/lithnet/access-manager/issues/new) for support
42 |
43 | ### Support for LAPS Web
44 | The Lithnet LAPS Web product is no longer actively supported. The repository and wiki will remain available for historical purposes. If you experience any issues with LAPS web, please migrate to Access Manager, and if the issue is still not solved, then please raise an [issue on the Access Manager GitHub page](https://github.com/lithnet/access-manager/issues/new)
45 |
46 | Organizations that have licensed Access Manager Enterprise edition are eligible for a fixed-term support for LAPS web, while they transition to Access Manager.
47 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2000
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lithnet.Laps.Web", "Lithnet.Laps.Web\Lithnet.Laps.Web.csproj", "{AFF2B8F3-9BF2-4BDB-A841-F13AA9F4CEDC}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {AFF2B8F3-9BF2-4BDB-A841-F13AA9F4CEDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {AFF2B8F3-9BF2-4BDB-A841-F13AA9F4CEDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {AFF2B8F3-9BF2-4BDB-A841-F13AA9F4CEDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {AFF2B8F3-9BF2-4BDB-A841-F13AA9F4CEDC}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {9CD0854C-BB55-4ACD-9C02-7944A982D6B9}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_Data/Templates/EmailAuditFailure.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 | {message}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Date
17 |
18 |
19 | {datetime}
20 |
21 |
22 |
23 |
24 | User SAM account name
25 |
26 |
27 | {user.SamAccountName}
28 |
29 |
30 |
31 |
32 | User diplay name
33 |
34 |
35 | {user.DisplayName}
36 |
37 |
38 |
39 |
40 | User DN
41 |
42 |
43 | {user.DistinguishedName}
44 |
45 |
46 |
47 |
48 | User principal name
49 |
50 |
51 | {user.UserPrincipalName}
52 |
53 |
54 |
55 |
56 | User SID
57 |
58 |
59 | {user.Sid}
60 |
61 |
62 |
63 |
64 |
65 | User IP
66 |
67 |
68 | {request.UnmaskedIPAddress}
69 |
70 |
71 |
72 |
73 |
74 | User Hostname
75 |
76 |
77 | {request.HostName}
78 |
79 |
80 |
81 |
82 |
83 | Requested computer name
84 |
85 |
86 | {requestedComputerName}
87 |
88 |
89 |
90 |
91 |
92 | Computer SAM account name
93 |
94 |
95 | {computer.SamAccountName}
96 |
97 |
98 |
99 |
100 | Computer DN
101 |
102 |
103 | {computer.DistinguishedName}
104 |
105 |
106 |
107 |
108 |
109 |
110 | Matched target ID
111 |
112 |
113 | {target.ID}
114 |
115 |
116 |
117 |
118 | Matched reader principal
119 |
120 |
121 | {reader.Principal}
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_Data/Templates/EmailAuditSuccess.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 | Date
9 |
10 |
11 | {datetime}
12 |
13 |
14 |
15 |
16 | User SAM account name
17 |
18 |
19 | {user.SamAccountName}
20 |
21 |
22 |
23 |
24 | User diplay name
25 |
26 |
27 | {user.DisplayName}
28 |
29 |
30 |
31 |
32 | User DN
33 |
34 |
35 | {user.DistinguishedName}
36 |
37 |
38 |
39 |
40 | User principal name
41 |
42 |
43 | {user.UserPrincipalName}
44 |
45 |
46 |
47 |
48 | User SID
49 |
50 |
51 | {user.Sid}
52 |
53 |
54 |
55 |
56 |
57 | User IP
58 |
59 |
60 | {request.UnmaskedIPAddress}
61 |
62 |
63 |
64 |
65 |
66 | User Hostname
67 |
68 |
69 | {request.HostName}
70 |
71 |
72 |
73 |
74 |
75 | Computer SAM account name
76 |
77 |
78 | {computer.SamAccountName}
79 |
80 |
81 |
82 |
83 | Computer DN
84 |
85 |
86 | {computer.DistinguishedName}
87 |
88 |
89 |
90 |
91 |
92 | Password expiry
93 |
94 |
95 | {computer.LapsExpiryDate}
96 |
97 |
98 |
99 |
100 |
101 | Matched target ID
102 |
103 |
104 | {target.ID}
105 |
106 |
107 |
108 |
109 | Matched reader principal
110 |
111 |
112 | {reader.Principal}
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_Data/Templates/LogAuditFailure.txt:
--------------------------------------------------------------------------------
1 | AUDIT: FAILURE
2 | Username: {user.SamAccountName}
3 | Name: {user.DisplayName}
4 | UPN: {user.UserPrincipalName}
5 | SID: {user.Sid}
6 | User DN: {user.DistinguishedName}
7 | Requestor IP: {request.UnmaskedIPAddress}
8 | Requestor Hostname: {request.HostName}
9 | Requested computer: {requestedComputerName}
10 | Computer name: {computer.SamAccountName}
11 | Computer DN: {computer.DistinguishedName}
12 | Target ID: {target.ID}
13 | Reader principal: {reader.Principal}
14 | Detail: {message}
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_Data/Templates/LogAuditSuccess.txt:
--------------------------------------------------------------------------------
1 | AUDIT: SUCCESS
2 | Username: {user.SamAccountName}
3 | Name: {user.DisplayName}
4 | UPN: {user.UserPrincipalName}
5 | SID: {user.Sid}
6 | User DN: {user.DistinguishedName}
7 | Requestor IP: {request.UnmaskedIPAddress}
8 | Requestor Hostname: {request.HostName}
9 | Computer name: {computer.SamAccountName}
10 | Computer DN: {computer.DistinguishedName}
11 | Password expiry: {computer.LapsExpiryDate}
12 | Target ID: {target.ID}
13 | Reader principal: {reader.Principal}
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_LocalResources/LogMessages.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | The user {0} requested the password for computer {1} which was not found in the directory
122 |
123 |
124 | {0} has requested the password for {1}
125 |
126 |
127 | The user {0} requested access to computer {1} but no targets exist for this computer
128 |
129 |
130 | The computer {0} requested by {1} did not have a LAPS password in the directory
131 |
132 |
133 | The user {0} requested access to computer {1} but does not match any of the reader principals that are allowed access to this computer
134 |
135 |
136 | An unhandled error occurred while processing the request for the password for {0} by user {1}
137 |
138 |
139 | No user claim was found with the type {0}
140 |
141 |
142 | The request could not be processed because the authenticated user was not found in the directory. Claim information:
143 | {0}
144 |
145 |
146 | Target rule requires password to change after {0}
147 |
148 |
149 | unknown
150 |
151 |
152 | LAP access denied for {user.SamAccountName} to {computer.SamAccountName}
153 |
154 |
155 | LAP for {computer.SamAccountName} accessed by {user.SamAccountName}
156 |
157 |
158 | AUDIT: FAILURE
159 | Username: {user.SamAccountName}
160 | Name: {user.DisplayName}
161 | UPN: {user.UserPrincipalName}
162 | SID: {user.Sid}
163 | User DN: {user.DistinguishedName}
164 | Computer Name: {computer.SamAccountName}
165 | Computer DN: {computer.DistinguishedName}
166 | Target ID: {target.ID}
167 | Reader principal: {reader.Principal}
168 | Detail: {message}
169 |
170 |
171 | AUDIT: SUCCESS
172 | Username: {user.SamAccountName}
173 | Name: {user.DisplayName}
174 | UPN: {user.UserPrincipalName}
175 | SID: {user.Sid}
176 | User DN: {user.DistinguishedName}
177 | Computer Name: {computer.SamAccountName}
178 | Computer DN: {computer.DistinguishedName}
179 | Target ID: {target.ID}
180 | Reader principal: {reader.Principal}
181 |
182 |
183 | Successfully authenticated and mapped directory user
184 | {0}
185 |
186 |
187 | The authentication provider returned an error
188 |
189 |
190 | An error occurred during the authorization code flow
191 |
192 |
193 | The user {0} on IP {1} has exceeded the maximum allowed number of requests per IP ({2} per {3} seconds)
194 |
195 |
196 | The user {0} on IP {1} has exceeded the maximum allowed number of requests per user ({2} per {3} seconds)
197 |
198 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_LocalResources/UIMessages.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Lithnet.Laps.Web.App_LocalResources {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | public class UIMessages {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal UIMessages() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | public static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Lithnet.Laps.Web.App_LocalResources.UIMessages", typeof(UIMessages).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | public static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized string similar to An authentication error occurred.
65 | ///
66 | public static string AuthNError {
67 | get {
68 | return ResourceManager.GetString("AuthNError", resourceCulture);
69 | }
70 | }
71 |
72 | ///
73 | /// Looks up a localized string similar to Request another password.
74 | ///
75 | public static string ButtonRequestAnotherPassword {
76 | get {
77 | return ResourceManager.GetString("ButtonRequestAnotherPassword", resourceCulture);
78 | }
79 | }
80 |
81 | ///
82 | /// Looks up a localized string similar to Request password.
83 | ///
84 | public static string ButtonRequestPassword {
85 | get {
86 | return ResourceManager.GetString("ButtonRequestPassword", resourceCulture);
87 | }
88 | }
89 |
90 | ///
91 | /// Looks up a localized string similar to Computer name.
92 | ///
93 | public static string ComputerName {
94 | get {
95 | return ResourceManager.GetString("ComputerName", resourceCulture);
96 | }
97 | }
98 |
99 | ///
100 | /// Looks up a localized string similar to Computer name is required.
101 | ///
102 | public static string ComputerNameIsRequired {
103 | get {
104 | return ResourceManager.GetString("ComputerNameIsRequired", resourceCulture);
105 | }
106 | }
107 |
108 | ///
109 | /// Looks up a localized string similar to The requested computer was not found in the directory.
110 | ///
111 | public static string ComputerNotFoundInDirectory {
112 | get {
113 | return ResourceManager.GetString("ComputerNotFoundInDirectory", resourceCulture);
114 | }
115 | }
116 |
117 | ///
118 | /// Looks up a localized string similar to Password details.
119 | ///
120 | public static string HeadingPasswordDetails {
121 | get {
122 | return ResourceManager.GetString("HeadingPasswordDetails", resourceCulture);
123 | }
124 | }
125 |
126 | ///
127 | /// Looks up a localized string similar to Request password.
128 | ///
129 | public static string HeadingRequestPassword {
130 | get {
131 | return ResourceManager.GetString("HeadingRequestPassword", resourceCulture);
132 | }
133 | }
134 |
135 | ///
136 | /// Looks up a localized string similar to You have been logged out. Please close all browser windows..
137 | ///
138 | public static string LoggedOut {
139 | get {
140 | return ResourceManager.GetString("LoggedOut", resourceCulture);
141 | }
142 | }
143 |
144 | ///
145 | /// Looks up a localized string similar to The requested computer does not have a LAPS password.
146 | ///
147 | public static string NoLapsPassword {
148 | get {
149 | return ResourceManager.GetString("NoLapsPassword", resourceCulture);
150 | }
151 | }
152 |
153 | ///
154 | /// Looks up a localized string similar to <not set>.
155 | ///
156 | public static string NoLapsPasswordPlaceholder {
157 | get {
158 | return ResourceManager.GetString("NoLapsPasswordPlaceholder", resourceCulture);
159 | }
160 | }
161 |
162 | ///
163 | /// Looks up a localized string similar to You are not authorized to access the password for this computer.
164 | ///
165 | public static string NotAuthorized {
166 | get {
167 | return ResourceManager.GetString("NotAuthorized", resourceCulture);
168 | }
169 | }
170 |
171 | ///
172 | /// Looks up a localized string similar to Password.
173 | ///
174 | public static string Password {
175 | get {
176 | return ResourceManager.GetString("Password", resourceCulture);
177 | }
178 | }
179 |
180 | ///
181 | /// Looks up a localized string similar to You have exceeded the maximum number of requests allowed in a specified period of time.
182 | ///
183 | public static string RateLimitError {
184 | get {
185 | return ResourceManager.GetString("RateLimitError", resourceCulture);
186 | }
187 | }
188 |
189 | ///
190 | /// Looks up a localized string similar to Your request could not be processed because your SSO identity could not be found in the directory.
191 | ///
192 | public static string SsoIdentityNotFound {
193 | get {
194 | return ResourceManager.GetString("SsoIdentityNotFound", resourceCulture);
195 | }
196 | }
197 |
198 | ///
199 | /// Looks up a localized string similar to An unexpected error occurred.
200 | ///
201 | public static string UnexpectedError {
202 | get {
203 | return ResourceManager.GetString("UnexpectedError", resourceCulture);
204 | }
205 | }
206 |
207 | ///
208 | /// Looks up a localized string similar to Valid until.
209 | ///
210 | public static string ValidUntil {
211 | get {
212 | return ResourceManager.GetString("ValidUntil", resourceCulture);
213 | }
214 | }
215 | }
216 | }
217 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_LocalResources/UIMessages.it.Designer.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_LocalResources/UIMessages.it.Designer.cs
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_LocalResources/UIMessages.it.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | The requested computer was not found in the directory
122 |
123 |
124 | Non sei autorizzato ad accedere alla password per questo computer
125 |
126 |
127 | La tua richiesta non può essere elaborata perché la tua identità non può essere trovata nella directory
128 |
129 |
130 | Il computer richiesto non ha una password di amministratore locale
131 |
132 |
133 | Si è verificato un errore imprevisto
134 |
135 |
136 | Il nome del computer è richiesto
137 |
138 |
139 | Si è verificato un errore di autenticazione
140 |
141 |
142 | Richiedi un'altra password
143 |
144 |
145 | Richiedi password
146 |
147 |
148 | Nomi del computer
149 |
150 |
151 | Dettagli della password
152 |
153 |
154 | Richiedi password
155 |
156 |
157 | Password
158 |
159 |
160 | Valido fino a
161 |
162 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_LocalResources/UIMessages.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | The requested computer was not found in the directory
122 |
123 |
124 | You are not authorized to access the password for this computer
125 |
126 |
127 | Your request could not be processed because your SSO identity could not be found in the directory
128 |
129 |
130 | The requested computer does not have a LAPS password
131 |
132 |
133 | An unexpected error occurred
134 |
135 |
136 | Computer name is required
137 |
138 |
139 | An authentication error occurred
140 |
141 |
142 | Request another password
143 |
144 |
145 | Request password
146 |
147 |
148 | Computer name
149 |
150 |
151 | Password details
152 |
153 |
154 | Request password
155 |
156 |
157 | Password
158 |
159 |
160 | Valid until
161 |
162 |
163 | <not set>
164 |
165 |
166 | You have exceeded the maximum number of requests allowed in a specified period of time
167 |
168 |
169 | You have been logged out. Please close all browser windows.
170 |
171 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_Start/BundleConfig.cs:
--------------------------------------------------------------------------------
1 | using System.Web;
2 | using System.Web.Optimization;
3 |
4 | namespace Lithnet.Laps.Web
5 | {
6 | public class BundleConfig
7 | {
8 | // For more information on bundling, visit https://go.microsoft.com/fwlink/?LinkId=301862
9 | public static void RegisterBundles(BundleCollection bundles)
10 | {
11 | bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
12 | "~/Scripts/jquery-{version}.js"));
13 |
14 | bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
15 | "~/Scripts/jquery.validate*"));
16 |
17 | bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
18 | "~/Scripts/bootstrap.js"));
19 |
20 | bundles.Add(new StyleBundle("~/Content/css").Include(
21 | "~/Content/bootstrap.css",
22 | "~/Content/site.css"));
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_Start/FilterConfig.cs:
--------------------------------------------------------------------------------
1 | using System.Web;
2 | using System.Web.Mvc;
3 |
4 | namespace Lithnet.Laps.Web
5 | {
6 | public class FilterConfig
7 | {
8 | public static void RegisterGlobalFilters(GlobalFilterCollection filters)
9 | {
10 | filters.Add(new HandleErrorAttribute());
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/App_Start/RouteConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Web;
5 | using System.Web.Mvc;
6 | using System.Web.Routing;
7 |
8 | namespace Lithnet.Laps.Web
9 | {
10 | public class RouteConfig
11 | {
12 | public static void RegisterRoutes(RouteCollection routes)
13 | {
14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
15 |
16 | routes.MapRoute(
17 | name: "Default",
18 | url: "{controller}/{action}/{id}",
19 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
20 | );
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/ConfigSection/AuditElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Web;
6 |
7 | namespace Lithnet.Laps.Web
8 | {
9 | public class AuditElement : ConfigurationElement
10 | {
11 | private const string PropNotifySuccess = "emailOnSuccess";
12 | private const string PropNotifyFailure = "emailOnFailure";
13 |
14 | private const string PropEmailAddresses = "emailAddresses";
15 |
16 | [ConfigurationProperty(PropNotifySuccess, IsRequired = false, DefaultValue = true)]
17 | public bool NotifySuccess => (bool) this[PropNotifySuccess];
18 |
19 | [ConfigurationProperty(PropNotifyFailure, IsRequired = false, DefaultValue = true)]
20 | public bool NotifyFailure => (bool)this[PropNotifyFailure];
21 |
22 | [ConfigurationProperty(PropEmailAddresses, IsRequired = false)]
23 | public string EmailAddresses => (string) this[PropEmailAddresses];
24 | }
25 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/ConfigSection/LapsConfigSection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Web;
6 |
7 | namespace Lithnet.Laps.Web
8 | {
9 | public class LapsConfigSection : ConfigurationSection
10 | {
11 | private const string SectionName = "lithnet-laps";
12 | private const string PropTargets = "targets";
13 | private const string PropTarget = "target";
14 | private const string PropAudit = "audit";
15 | private const string PropRateLimitIP = "rate-limit-ip";
16 | private const string PropRateLimitUser = "rate-limit-user";
17 |
18 |
19 | [ConfigurationProperty(PropTargets)]
20 | [ConfigurationCollection(typeof(TargetCollection), AddItemName = PropTarget, CollectionType = ConfigurationElementCollectionType.BasicMap)]
21 | public TargetCollection Targets => (TargetCollection)this[PropTargets];
22 |
23 | internal static LapsConfigSection GetConfiguration()
24 | {
25 | LapsConfigSection section = (LapsConfigSection)ConfigurationManager.GetSection(SectionName);
26 |
27 | if (section == null)
28 | {
29 | section = new LapsConfigSection();
30 | }
31 |
32 | return section;
33 | }
34 |
35 | [ConfigurationProperty(LapsConfigSection.PropAudit, IsRequired = false)]
36 | public AuditElement Audit => (AuditElement)this[LapsConfigSection.PropAudit];
37 |
38 | [ConfigurationProperty(PropRateLimitIP, IsRequired = false)]
39 | public RateLimitIPElement RateLimitIP => (RateLimitIPElement)this[PropRateLimitIP];
40 |
41 | [ConfigurationProperty(PropRateLimitUser, IsRequired = false)]
42 | public RateLimitUserElement RateLimitUser => (RateLimitUserElement)this[PropRateLimitUser];
43 |
44 | internal static LapsConfigSection Configuration { get; private set; }
45 |
46 | static LapsConfigSection()
47 | {
48 | LapsConfigSection.Configuration = LapsConfigSection.GetConfiguration();
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/ConfigSection/RateLimitIPElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Web;
6 |
7 | namespace Lithnet.Laps.Web
8 | {
9 | public class RateLimitIPElement : ConfigurationElement
10 | {
11 | private const string PropEnabled = "enabled";
12 | private const string PropReqPerMinute = "requestsPerMinute";
13 | private const string PropReqPerHour = "requestsPerHour";
14 | private const string PropReqPerDay = "requestsPerDay";
15 | private const string PropThrottleOnXffIP = "rateLimitOnXffIP";
16 |
17 | [ConfigurationProperty(PropEnabled, IsRequired = false, DefaultValue = true)]
18 | public bool Enabled => (bool) this[PropEnabled];
19 |
20 | [ConfigurationProperty(PropReqPerMinute, IsRequired = false, DefaultValue = 10)]
21 | public int ReqPerMinute => (int) this[PropReqPerMinute];
22 |
23 | [ConfigurationProperty(PropReqPerHour, IsRequired = false, DefaultValue = 50)]
24 | public int ReqPerHour => (int) this[PropReqPerHour];
25 |
26 | [ConfigurationProperty(PropReqPerDay, IsRequired = false, DefaultValue = 100)]
27 | public int ReqPerDay => (int) this[PropReqPerDay];
28 |
29 | [ConfigurationProperty(PropThrottleOnXffIP, IsRequired = false, DefaultValue = false)]
30 | public bool ThrottleOnXffIP => (bool)this[PropThrottleOnXffIP];
31 | }
32 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/ConfigSection/RateLimitUserElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Web;
6 |
7 | namespace Lithnet.Laps.Web
8 | {
9 | public class RateLimitUserElement : ConfigurationElement
10 | {
11 | private const string PropEnabled = "enabled";
12 | private const string PropReqPerMinute = "requestsPerMinute";
13 | private const string PropReqPerHour = "requestsPerHour";
14 | private const string PropReqPerDay = "requestsPerDay";
15 |
16 | [ConfigurationProperty(PropEnabled, IsRequired = false, DefaultValue = true)]
17 | public bool Enabled => (bool) this[PropEnabled];
18 |
19 | [ConfigurationProperty(PropReqPerMinute, IsRequired = false, DefaultValue = 10)]
20 | public int ReqPerMinute => (int) this[PropReqPerMinute];
21 |
22 | [ConfigurationProperty(PropReqPerHour, IsRequired = false, DefaultValue = 50)]
23 | public int ReqPerHour => (int) this[PropReqPerHour];
24 |
25 | [ConfigurationProperty(PropReqPerDay, IsRequired = false, DefaultValue = 100)]
26 | public int ReqPerDay => (int) this[PropReqPerDay];
27 | }
28 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/ConfigSection/ReaderCollection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Web;
6 |
7 | namespace Lithnet.Laps.Web
8 | {
9 | public class ReaderCollection : ConfigurationElementCollection
10 | {
11 | public ReaderElement this[int index]
12 | {
13 | get => (ReaderElement) this.BaseGet(index);
14 | set
15 | {
16 | if (this.BaseGet(index) != null)
17 | {
18 | this.BaseRemoveAt(index);
19 | }
20 |
21 | this.BaseAdd(index, value);
22 | }
23 | }
24 |
25 | public void Add(ReaderElement reader)
26 | {
27 | this.BaseAdd(reader);
28 | }
29 |
30 | public void Clear()
31 | {
32 | this.BaseClear();
33 | }
34 |
35 | protected override ConfigurationElement CreateNewElement()
36 | {
37 | return new ReaderElement();
38 | }
39 |
40 | protected override object GetElementKey(ConfigurationElement element)
41 | {
42 | return ((ReaderElement) element).Principal;
43 | }
44 |
45 | public void Remove(ReaderElement reader)
46 | {
47 | this.BaseRemove(reader.Principal);
48 | }
49 |
50 | public void RemoveAt(int index)
51 | {
52 | this.BaseRemoveAt(index);
53 | }
54 |
55 | public void Remove(string name)
56 | {
57 | this.BaseRemove(name);
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/ConfigSection/ReaderElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Web;
6 |
7 | namespace Lithnet.Laps.Web
8 | {
9 | public class ReaderElement : ConfigurationElement
10 | {
11 | private const string PropAudit = "audit";
12 | private const string PropPrincipal = "principal";
13 |
14 | [ConfigurationProperty(ReaderElement.PropAudit, IsRequired = false)]
15 | public AuditElement Audit => (AuditElement)this[ReaderElement.PropAudit];
16 |
17 | [ConfigurationProperty(PropPrincipal, IsRequired = true, IsKey = true)]
18 | public string Principal => (string)this[PropPrincipal];
19 | }
20 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/ConfigSection/TargetCollection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Web;
6 |
7 | namespace Lithnet.Laps.Web
8 | {
9 | public class TargetCollection : ConfigurationElementCollection
10 | {
11 | public TargetElement this[int index]
12 | {
13 | get => (TargetElement) this.BaseGet(index);
14 | set
15 | {
16 | if (this.BaseGet(index) != null)
17 | {
18 | this.BaseRemoveAt(index);
19 | }
20 |
21 | this.BaseAdd(index, value);
22 | }
23 | }
24 |
25 | public void Add(TargetElement reader)
26 | {
27 | this.BaseAdd(reader);
28 | }
29 |
30 | public void Clear()
31 | {
32 | this.BaseClear();
33 | }
34 |
35 | protected override ConfigurationElement CreateNewElement()
36 | {
37 | return new TargetElement();
38 | }
39 |
40 | protected override object GetElementKey(ConfigurationElement element)
41 | {
42 | return ((TargetElement) element).Name;
43 | }
44 |
45 | public void Remove(TargetElement reader)
46 | {
47 | this.BaseRemove(reader.Name);
48 | }
49 |
50 | public void RemoveAt(int index)
51 | {
52 | this.BaseRemoveAt(index);
53 | }
54 |
55 | public void Remove(string name)
56 | {
57 | this.BaseRemove(name);
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/ConfigSection/TargetElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.DirectoryServices;
5 | using System.Linq;
6 | using System.Security.Principal;
7 | using System.Web;
8 | using System.DirectoryServices.AccountManagement;
9 |
10 | namespace Lithnet.Laps.Web
11 | {
12 | public class TargetElement : ConfigurationElement
13 | {
14 | private Principal principal;
15 |
16 | private const string PropAudit = "audit";
17 | private const string PropReaders = "readers";
18 | private const string PropReader = "reader";
19 | private const string PropExpireAfter = "expire-after";
20 | private const string PropID = "name";
21 | private const string PropIDType = "type";
22 |
23 | [ConfigurationProperty(TargetElement.PropAudit, IsRequired = false)]
24 | public AuditElement Audit => (AuditElement) this[TargetElement.PropAudit];
25 |
26 | [ConfigurationProperty(PropIDType, IsRequired = false)]
27 | public TargetType Type => (TargetType) this[PropIDType];
28 |
29 | [ConfigurationProperty(PropID, IsRequired = true, IsKey = true)]
30 | public string Name => (string) this[PropID];
31 |
32 | [ConfigurationProperty(TargetElement.PropExpireAfter, IsRequired = false)]
33 | public string ExpireAfter => (string) this[TargetElement.PropExpireAfter];
34 |
35 | [ConfigurationProperty(PropReaders, IsRequired = true)]
36 | [ConfigurationCollection(typeof(ReaderCollection), AddItemName = PropReader, CollectionType = ConfigurationElementCollectionType.BasicMap)]
37 | public ReaderCollection Readers => (ReaderCollection) this[PropReaders];
38 |
39 | internal Principal PrincipalObject
40 | {
41 | get
42 | {
43 | if (this.principal == null)
44 | {
45 | PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
46 | this.principal = Principal.FindByIdentity(ctx, this.Name);
47 | }
48 |
49 | return this.principal;
50 | }
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/ConfigSection/TargetType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Web;
6 |
7 | namespace Lithnet.Laps.Web
8 | {
9 | public enum TargetType
10 | {
11 | Computer,
12 | Group,
13 | Container
14 | }
15 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/Site.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: Inconsolata;
3 | src: url('webfonts/Inconsolata-Regular.ttf');
4 | }
5 |
6 | body {
7 | color: #666;
8 | /*font-family: "Open Sans",Arial,Helvetica,sans-serif;*/
9 | font-size: 13px;
10 | }
11 |
12 | .app-header {
13 | display: block;
14 | font-size: 18px;
15 | font-weight: 300;
16 | color: #242424;
17 | padding: 15px 13px;
18 | border-bottom-width: 0px;
19 | border-bottom-style: solid;
20 | border-bottom-color: rgba(0, 0, 0, .1);
21 | background: white;
22 | position: relative;
23 | border: 1px solid #dcdcdc;
24 | align-items: center;
25 | text-align: center;
26 | }
27 |
28 | .center-content {
29 | align-items: center;
30 | text-align: center;
31 | }
32 |
33 | .app-logo {
34 | max-width: 200px;
35 | }
36 |
37 | .app-title {
38 | font-weight: 400;
39 | }
40 |
41 | .content {
42 | width: 500px;
43 | margin-left: auto;
44 | margin-right: auto;
45 | padding: 10px;
46 | }
47 |
48 | .form-container {
49 | background-color: #fefbfb;
50 | border: 1px solid #dcdcdc;
51 | position: relative;
52 | }
53 |
54 | .form-container header {
55 | display: block;
56 | font-size: 18px;
57 | font-weight: 300;
58 | color: #242424;
59 | padding: 15px 13px;
60 | margin: 0;
61 | border-bottom-width: 1px;
62 | border-bottom-style: solid;
63 | border-bottom-color: rgba(0,0,0,.1);
64 | background: rgba(248,248,248,.9);
65 | position: relative;
66 | }
67 |
68 | .form-container fieldset {
69 | display: block;
70 | padding: 25px 14px 5px;
71 | border: none;
72 | background: rgba(255,255,255,.9);
73 | position: relative;
74 | }
75 |
76 | .form-container section {
77 | margin-bottom: 15px;
78 | position: relative;
79 | }
80 |
81 | .form-container label.title {
82 | display: block;
83 | margin-bottom: 3px;
84 | line-height: 19px;
85 | font-weight: 600;
86 | font-size: 13px;
87 | color: #333;
88 | }
89 |
90 | .form-container label.input {
91 | position: relative;
92 | display: block;
93 | font-weight: 400;
94 | max-width: 100%;
95 | font-size: 13px;
96 | }
97 |
98 | .form-container i.icon-append {
99 | border-color: #bdbdbd;
100 | color: #a2a2a2;
101 | right: 5px;
102 | padding-left: 3px;
103 | border-left-width: 1px;
104 | border-left-style: solid;
105 | position: absolute;
106 | top: 5px;
107 | width: 22px;
108 | height: 22px;
109 | font-size: 14px;
110 | line-height: 22px;
111 | text-align: center;
112 | }
113 |
114 | .form-container input.dataEntry {
115 | display: block;
116 | padding-right: 37px;
117 | border-color: #bdbdbd;
118 | width: 100%;
119 | height: 32px;
120 | padding: 5px 10px;
121 | outline: 0;
122 | border-width: 1px;
123 | border-style: solid;
124 | border-radius: 0;
125 | background: #fff;
126 | color: #404040;
127 | }
128 |
129 | .form-container .tooltip {
130 | position: absolute;
131 | bottom: 100%;
132 | margin-bottom: 15px;
133 | z-index: 99999;
134 | left: -9999px;
135 | padding: 2px 8px 3px;
136 | font-size: 11px;
137 | line-height: 16px;
138 | font-weight: 400;
139 | background: rgba(0,0,0,.9);
140 | color: #fff;
141 | opacity: 0;
142 | }
143 |
144 | .form-container .tooltip::after {
145 | top: 100%;
146 | right: 11px;
147 | border-top: 4px solid rgba(0,0,0,.9);
148 | border-right: 4px solid transparent;
149 | border-left: 4px solid transparent;
150 | content: '';
151 | position: absolute;
152 | margin: 0;
153 | padding: 0;
154 | }
155 |
156 | .form-container footer {
157 | display: block;
158 | padding: 7px 14px 15px;
159 | border-top: 1px solid rgba(0,0,0,.1);
160 | background: rgba(248,248,248,.9);
161 | margin: 0;
162 | }
163 |
164 | .form-container .error {
165 | color: #8f2626;
166 | text-align: center;
167 | display: block;
168 | }
169 |
170 | .resultsText {
171 | border-color: #f0f0f0;
172 | height: 32px;
173 | padding: 5px 10px;
174 | outline: 0;
175 | border-width: 1px;
176 | border-style: solid;
177 | border-radius: 0;
178 | background: #fbfbfb;
179 | color: #404040;
180 | width: 100%;
181 | display: table-cell;
182 | position: relative;
183 | }
184 |
185 | .input-group {
186 | width: 100%;
187 | display: table;
188 | }
189 |
190 | .input-group-append {
191 | width: 1%;
192 | vertical-align: middle;
193 | display: table-cell;
194 | height: 32px;
195 | }
196 |
197 | .input-group-append button {
198 | width: 32px;
199 | height: 32px;
200 | }
201 |
202 | .password-field {
203 | font-family: Inconsolata, Consolas, Courier New, Courier, monospace;
204 | font-size: large;
205 | font-weight: bold;
206 | }
207 |
208 | #copy-button {
209 | margin-left: 10px;
210 | }
211 |
212 | .password-char-digit {
213 | color: darkblue;
214 | display: inline-block;
215 | }
216 |
217 | .password-char-letter {
218 | color: slategray;
219 | display: inline-block;
220 | }
221 |
222 | .password-char-other {
223 | color: darkred;
224 | display: inline-block;
225 | }
226 |
227 | @media only screen and (max-width: 600px) {
228 | .form-container {
229 | width: auto;
230 | margin-right: 0;
231 | margin-left: 0;
232 | border: 0;
233 | margin-top: 0;
234 | box-shadow: none;
235 | }
236 |
237 | /*.auth-container .auth-content {
238 | max-width: 316px;
239 | margin: 0 auto;
240 | }*/
241 | }
242 |
243 | @media only screen and (max-device-width: 480px) {
244 | .content {
245 | margin-top: 0;
246 | width: 100%;
247 | }
248 | }
249 |
250 | @media only screen and (max-width: 400px) {
251 | .content {
252 | width: 100%;
253 | }
254 | }
255 |
256 | @media only screen and (max-height: 750px) {
257 | .content {
258 | margin-top: 0;
259 | }
260 | }
261 |
262 | .logout-link {
263 | color: #777;
264 | }
265 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/bootstrap-reboot.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
3 | * Copyright 2011-2019 The Bootstrap Authors
4 | * Copyright 2011-2019 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */
8 | *,
9 | *::before,
10 | *::after {
11 | box-sizing: border-box;
12 | }
13 |
14 | html {
15 | font-family: sans-serif;
16 | line-height: 1.15;
17 | -webkit-text-size-adjust: 100%;
18 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
19 | }
20 |
21 | article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
22 | display: block;
23 | }
24 |
25 | body {
26 | margin: 0;
27 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
28 | font-size: 1rem;
29 | font-weight: 400;
30 | line-height: 1.5;
31 | color: #212529;
32 | text-align: left;
33 | background-color: #fff;
34 | }
35 |
36 | [tabindex="-1"]:focus {
37 | outline: 0 !important;
38 | }
39 |
40 | hr {
41 | box-sizing: content-box;
42 | height: 0;
43 | overflow: visible;
44 | }
45 |
46 | h1, h2, h3, h4, h5, h6 {
47 | margin-top: 0;
48 | margin-bottom: 0.5rem;
49 | }
50 |
51 | p {
52 | margin-top: 0;
53 | margin-bottom: 1rem;
54 | }
55 |
56 | abbr[title],
57 | abbr[data-original-title] {
58 | text-decoration: underline;
59 | -webkit-text-decoration: underline dotted;
60 | text-decoration: underline dotted;
61 | cursor: help;
62 | border-bottom: 0;
63 | -webkit-text-decoration-skip-ink: none;
64 | text-decoration-skip-ink: none;
65 | }
66 |
67 | address {
68 | margin-bottom: 1rem;
69 | font-style: normal;
70 | line-height: inherit;
71 | }
72 |
73 | ol,
74 | ul,
75 | dl {
76 | margin-top: 0;
77 | margin-bottom: 1rem;
78 | }
79 |
80 | ol ol,
81 | ul ul,
82 | ol ul,
83 | ul ol {
84 | margin-bottom: 0;
85 | }
86 |
87 | dt {
88 | font-weight: 700;
89 | }
90 |
91 | dd {
92 | margin-bottom: .5rem;
93 | margin-left: 0;
94 | }
95 |
96 | blockquote {
97 | margin: 0 0 1rem;
98 | }
99 |
100 | b,
101 | strong {
102 | font-weight: bolder;
103 | }
104 |
105 | small {
106 | font-size: 80%;
107 | }
108 |
109 | sub,
110 | sup {
111 | position: relative;
112 | font-size: 75%;
113 | line-height: 0;
114 | vertical-align: baseline;
115 | }
116 |
117 | sub {
118 | bottom: -.25em;
119 | }
120 |
121 | sup {
122 | top: -.5em;
123 | }
124 |
125 | a {
126 | color: #007bff;
127 | text-decoration: none;
128 | background-color: transparent;
129 | }
130 |
131 | a:hover {
132 | color: #0056b3;
133 | text-decoration: underline;
134 | }
135 |
136 | a:not([href]):not([tabindex]) {
137 | color: inherit;
138 | text-decoration: none;
139 | }
140 |
141 | a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
142 | color: inherit;
143 | text-decoration: none;
144 | }
145 |
146 | a:not([href]):not([tabindex]):focus {
147 | outline: 0;
148 | }
149 |
150 | pre,
151 | code,
152 | kbd,
153 | samp {
154 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
155 | font-size: 1em;
156 | }
157 |
158 | pre {
159 | margin-top: 0;
160 | margin-bottom: 1rem;
161 | overflow: auto;
162 | }
163 |
164 | figure {
165 | margin: 0 0 1rem;
166 | }
167 |
168 | img {
169 | vertical-align: middle;
170 | border-style: none;
171 | }
172 |
173 | svg {
174 | overflow: hidden;
175 | vertical-align: middle;
176 | }
177 |
178 | table {
179 | border-collapse: collapse;
180 | }
181 |
182 | caption {
183 | padding-top: 0.75rem;
184 | padding-bottom: 0.75rem;
185 | color: #6c757d;
186 | text-align: left;
187 | caption-side: bottom;
188 | }
189 |
190 | th {
191 | text-align: inherit;
192 | }
193 |
194 | label {
195 | display: inline-block;
196 | margin-bottom: 0.5rem;
197 | }
198 |
199 | button {
200 | border-radius: 0;
201 | }
202 |
203 | button:focus {
204 | outline: 1px dotted;
205 | outline: 5px auto -webkit-focus-ring-color;
206 | }
207 |
208 | input,
209 | button,
210 | select,
211 | optgroup,
212 | textarea {
213 | margin: 0;
214 | font-family: inherit;
215 | font-size: inherit;
216 | line-height: inherit;
217 | }
218 |
219 | button,
220 | input {
221 | overflow: visible;
222 | }
223 |
224 | button,
225 | select {
226 | text-transform: none;
227 | }
228 |
229 | select {
230 | word-wrap: normal;
231 | }
232 |
233 | button,
234 | [type="button"],
235 | [type="reset"],
236 | [type="submit"] {
237 | -webkit-appearance: button;
238 | }
239 |
240 | button:not(:disabled),
241 | [type="button"]:not(:disabled),
242 | [type="reset"]:not(:disabled),
243 | [type="submit"]:not(:disabled) {
244 | cursor: pointer;
245 | }
246 |
247 | button::-moz-focus-inner,
248 | [type="button"]::-moz-focus-inner,
249 | [type="reset"]::-moz-focus-inner,
250 | [type="submit"]::-moz-focus-inner {
251 | padding: 0;
252 | border-style: none;
253 | }
254 |
255 | input[type="radio"],
256 | input[type="checkbox"] {
257 | box-sizing: border-box;
258 | padding: 0;
259 | }
260 |
261 | input[type="date"],
262 | input[type="time"],
263 | input[type="datetime-local"],
264 | input[type="month"] {
265 | -webkit-appearance: listbox;
266 | }
267 |
268 | textarea {
269 | overflow: auto;
270 | resize: vertical;
271 | }
272 |
273 | fieldset {
274 | min-width: 0;
275 | padding: 0;
276 | margin: 0;
277 | border: 0;
278 | }
279 |
280 | legend {
281 | display: block;
282 | width: 100%;
283 | max-width: 100%;
284 | padding: 0;
285 | margin-bottom: .5rem;
286 | font-size: 1.5rem;
287 | line-height: inherit;
288 | color: inherit;
289 | white-space: normal;
290 | }
291 |
292 | progress {
293 | vertical-align: baseline;
294 | }
295 |
296 | [type="number"]::-webkit-inner-spin-button,
297 | [type="number"]::-webkit-outer-spin-button {
298 | height: auto;
299 | }
300 |
301 | [type="search"] {
302 | outline-offset: -2px;
303 | -webkit-appearance: none;
304 | }
305 |
306 | [type="search"]::-webkit-search-decoration {
307 | -webkit-appearance: none;
308 | }
309 |
310 | ::-webkit-file-upload-button {
311 | font: inherit;
312 | -webkit-appearance: button;
313 | }
314 |
315 | output {
316 | display: inline-block;
317 | }
318 |
319 | summary {
320 | display: list-item;
321 | cursor: pointer;
322 | }
323 |
324 | template {
325 | display: none;
326 | }
327 |
328 | [hidden] {
329 | display: none !important;
330 | }
331 | /*# sourceMappingURL=bootstrap-reboot.css.map */
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/bootstrap-reboot.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
3 | * Copyright 2011-2019 The Bootstrap Authors
4 | * Copyright 2011-2019 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/fontawesome/fa-brands.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face {
6 | font-family: 'Font Awesome 5 Brands';
7 | font-style: normal;
8 | font-weight: normal;
9 | src: url("../webfonts/fa-brands-400.eot");
10 | src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); }
11 |
12 | .fab {
13 | font-family: 'Font Awesome 5 Brands'; }
14 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/fontawesome/fa-brands.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face{font-family:Font Awesome\ 5 Brands;font-style:normal;font-weight:400;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:Font Awesome\ 5 Brands}
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/fontawesome/fa-regular.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face {
6 | font-family: 'Font Awesome 5 Free';
7 | font-style: normal;
8 | font-weight: 400;
9 | src: url("../webfonts/fa-regular-400.eot");
10 | src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); }
11 |
12 | .far {
13 | font-family: 'Font Awesome 5 Free';
14 | font-weight: 400; }
15 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/fontawesome/fa-regular.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:400;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-family:Font Awesome\ 5 Free;font-weight:400}
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/fontawesome/fa-solid.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face {
6 | font-family: 'Font Awesome 5 Free';
7 | font-style: normal;
8 | font-weight: 900;
9 | src: url("../webfonts/fa-solid-900.eot");
10 | src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); }
11 |
12 | .fa,
13 | .fas {
14 | font-family: 'Font Awesome 5 Free';
15 | font-weight: 900; }
16 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/fontawesome/fa-solid.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:900;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:Font Awesome\ 5 Free;font-weight:900}
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/Inconsolata-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/Inconsolata-Regular.ttf
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-brands-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-brands-400.eot
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-brands-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-brands-400.ttf
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-brands-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-brands-400.woff
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-brands-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-brands-400.woff2
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-regular-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-regular-400.eot
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-regular-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-regular-400.ttf
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-regular-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-regular-400.woff
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-regular-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-regular-400.woff2
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-solid-900.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-solid-900.eot
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-solid-900.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-solid-900.ttf
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-solid-900.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-solid-900.woff
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-solid-900.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Content/webfonts/fa-solid-900.woff2
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Controllers/HomeController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Web;
5 | using System.Web.Mvc;
6 | using Lithnet.Laps.Web.Models;
7 |
8 | namespace Lithnet.Laps.Web.Controllers
9 | {
10 | public class HomeController : Controller
11 | {
12 | public ActionResult Index()
13 | {
14 | return this.RedirectToAction("Get", "Lap");
15 | }
16 |
17 | public ActionResult AuthNError()
18 | {
19 | return this.View();
20 | }
21 |
22 | public ActionResult SignOut()
23 | {
24 | if (this.Request.GetOwinContext().Authentication.User.Identity.IsAuthenticated)
25 | {
26 | this.Request.GetOwinContext()
27 | .Authentication
28 | .SignOut(this.HttpContext.GetOwinContext()
29 | .Authentication.GetAuthenticationTypes()
30 | .Select(o => o.AuthenticationType).ToArray());
31 | }
32 |
33 | return this.View("LogOut");
34 | }
35 |
36 | public ActionResult LogOut()
37 | {
38 | return this.View();
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Exceptions/NoMatchingTargetException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Web;
5 |
6 | namespace Lithnet.Laps.Web
7 | {
8 | [System.Serializable]
9 | public class NoMatchingTargetException : Exception
10 | {
11 | public NoMatchingTargetException()
12 | {
13 | }
14 |
15 | public NoMatchingTargetException(string message)
16 | : base(message)
17 | {
18 | }
19 |
20 | public NoMatchingTargetException(string message, Exception inner)
21 | : base(message, inner)
22 | {
23 | }
24 |
25 |
26 | protected NoMatchingTargetException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
27 | : base(info, context)
28 | {
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Global.asax:
--------------------------------------------------------------------------------
1 | <%@ Application Codebehind="Global.asax.cs" Inherits="Lithnet.Laps.Web.MvcApplication" Language="C#" %>
2 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Global.asax.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.DirectoryServices.AccountManagement;
5 | using System.Linq;
6 | using System.Web;
7 | using System.Web.Mvc;
8 | using System.Web.Optimization;
9 | using System.Web.Routing;
10 |
11 | namespace Lithnet.Laps.Web
12 | {
13 | public class MvcApplication : System.Web.HttpApplication
14 | {
15 | protected void Application_Start()
16 | {
17 | AreaRegistration.RegisterAllAreas();
18 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
19 | RouteConfig.RegisterRoutes(RouteTable.Routes);
20 | BundleConfig.RegisterBundles(BundleTable.Bundles);
21 | }
22 |
23 | public static bool CanLogout => Startup.CanLogout && (HttpContext.Current?.User?.Identity?.IsAuthenticated ?? false);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Internal/Directory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.DirectoryServices;
4 | using System.DirectoryServices.AccountManagement;
5 | using System.Linq;
6 | using System.Security.Principal;
7 | using System.Web;
8 |
9 | namespace Lithnet.Laps.Web
10 | {
11 | internal static class Directory
12 | {
13 | public const string AttrSamAccountName = "samAccountName";
14 | public const string AttrMsMcsAdmPwd = "ms-Mcs-AdmPwd";
15 | public const string AttrMsMcsAdmPwdExpirationTime = "ms-Mcs-AdmPwdExpirationTime";
16 |
17 | internal static bool IsPrincipalInOu(Principal p, string ou)
18 | {
19 | DirectorySearcher d = new DirectorySearcher();
20 | d.SearchRoot = new DirectoryEntry($"LDAP://{ou}");
21 | d.SearchScope = SearchScope.Subtree;
22 | d.Filter = $"objectGuid={p.Guid.ToOctetString()}";
23 |
24 | return d.FindOne() != null;
25 | }
26 |
27 | internal static ComputerPrincipal GetComputerPrincipal(string name)
28 | {
29 | PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
30 | return ComputerPrincipal.FindByIdentity(ctx, name);
31 | }
32 |
33 | internal static GroupPrincipal GetGroupPrincipal(string name)
34 | {
35 | PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
36 | return GroupPrincipal.FindByIdentity(ctx, name);
37 | }
38 |
39 | internal static Principal GetPrincipal(string name)
40 | {
41 | PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
42 | return Principal.FindByIdentity(ctx, name);
43 | }
44 |
45 | internal static Principal GetPrincipal(IdentityType type, string name)
46 | {
47 | PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
48 | return Principal.FindByIdentity(ctx, type, name);
49 | }
50 |
51 | internal static bool IsPrincipalInGroup(Principal p, GroupPrincipal group)
52 | {
53 | if (group?.Sid == null || group.Sid.BinaryLength == 0)
54 | {
55 | return false;
56 | }
57 |
58 | byte[] groupSid = new byte[group.Sid.BinaryLength];
59 | group.Sid.GetBinaryForm(groupSid, 0);
60 | return IsPrincipalInGroup(p, groupSid);
61 | }
62 |
63 | private static bool IsPrincipalInGroup(Principal p, byte[] groupSid)
64 | {
65 | SearchResult result = GetDirectoryEntry(p, "tokenGroups");
66 |
67 | if (result == null)
68 | {
69 | return false;
70 | }
71 |
72 | foreach (byte[] value in result.Properties["tokenGroups"].OfType())
73 | {
74 | if (groupSid.SequenceEqual(value))
75 | {
76 | return true;
77 | }
78 | }
79 |
80 | return false;
81 | }
82 |
83 | internal static SearchResult GetDirectoryEntry(Principal p, params string[] propertiesToLoad)
84 | {
85 | return GetDirectoryEntry(p.DistinguishedName, propertiesToLoad);
86 | }
87 |
88 | internal static SearchResult GetDirectoryEntry(string dn, params string[] propertiesToLoad)
89 | {
90 | DirectorySearcher d = new DirectorySearcher();
91 | d.SearchRoot = new DirectoryEntry($"LDAP://{dn}");
92 | d.SearchScope = SearchScope.Base;
93 | d.Filter = $"objectClass=*";
94 | foreach (string prop in propertiesToLoad)
95 | {
96 | d.PropertiesToLoad.Add(prop);
97 | }
98 |
99 | return d.FindOne();
100 | }
101 |
102 | internal static string ToOctetString(this Guid? guid)
103 | {
104 | if (!guid.HasValue)
105 | {
106 | return null;
107 | }
108 |
109 | return $"\\{string.Join("\\", guid.Value.ToByteArray().Select(t => t.ToString("X2")))}";
110 | }
111 | }
112 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Internal/EventIDs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Web;
5 |
6 | namespace Lithnet.Laps.Web
7 | {
8 | internal static class EventIDs
9 | {
10 | public const int PasswordAccessed = 200;
11 | public const int UserAuthenticated = 201;
12 | public const int UserRequestedPassword = 202;
13 |
14 | public const int SsoIdentityNotFound = 400;
15 | public const int ComputerNotFound = 401;
16 | public const int LapsPasswordNotPresent = 402;
17 |
18 | public const int AuthZFailedNoReaderPrincipalMatch = 500;
19 | public const int AuthZFailedNoTargetMatch = 501;
20 | public const int RateLimitExceededIP = 502;
21 | public const int RateLimitExceededUser = 503;
22 |
23 | public const int UnexpectedError = 600;
24 | public const int AuditErrorCannotSendSuccessEmail = 601;
25 | public const int AuditErrorCannotSendFailureEmail = 602;
26 | public const int ErrorLoadingTemplateResource = 603;
27 |
28 | public const int OidcAuthZCodeError = 700;
29 | public const int OwinAuthNError = 701;
30 | }
31 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Internal/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.DirectoryServices;
4 | using System.DirectoryServices.AccountManagement;
5 | using System.Linq;
6 | using System.Security.Claims;
7 | using System.Text;
8 | using System.Web;
9 |
10 | namespace Lithnet.Laps.Web
11 | {
12 | internal static class Extensions
13 | {
14 | public static string GetXffList(this HttpRequest request)
15 | {
16 | return request.ServerVariables["HTTP_X_FORWARDED_FOR"];
17 | }
18 |
19 | public static string GetXffIP(this HttpRequest request)
20 | {
21 | return request.GetXffList()?.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)?.FirstOrDefault();
22 | }
23 |
24 | public static string GetUnmaskedIP(this HttpRequest request)
25 | {
26 | string ip = request.GetXffIP();
27 |
28 | return string.IsNullOrWhiteSpace(ip) ? request.UserHostAddress : ip;
29 | }
30 |
31 | public static string GetXffList(this HttpRequestBase request)
32 | {
33 | return request.ServerVariables["HTTP_X_FORWARDED_FOR"];
34 | }
35 |
36 | public static string GetXffIP(this HttpRequestBase request)
37 | {
38 | return request.GetXffList()?.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)?.FirstOrDefault();
39 | }
40 |
41 | public static string GetUnmaskedIP(this HttpRequestBase request)
42 | {
43 | string ip = request.GetXffIP();
44 |
45 | return string.IsNullOrWhiteSpace(ip) ? request.UserHostAddress : ip;
46 | }
47 |
48 |
49 | public static UserPrincipal FindUserPrincipalByClaim(this ClaimsIdentity p, IdentityType identityType, params string[] claimNames)
50 | {
51 | foreach (string claimName in claimNames)
52 | {
53 | Claim c = p.FindFirst(claimName);
54 | if (c != null)
55 | {
56 | return UserPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain), identityType, c.Value);
57 | }
58 | }
59 |
60 | return null;
61 | }
62 |
63 | public static string ToClaimList(this ClaimsIdentity p)
64 | {
65 | StringBuilder builder = new StringBuilder();
66 | foreach (Claim c in p.Claims)
67 | {
68 | builder.Append(c.Type).Append(": ").AppendLine(c.Value);
69 | }
70 |
71 | return builder.ToString();
72 | }
73 |
74 | public static DateTime? GetPropertyDateTimeFromLong(this SearchResult result, string propertyName)
75 | {
76 | if (!result.Properties.Contains(propertyName))
77 | {
78 | return null;
79 | }
80 |
81 | long value = (long)result.Properties[propertyName][0];
82 | return DateTime.FromFileTimeUtc(value).ToLocalTime();
83 | }
84 |
85 | public static string GetPropertyString(this SearchResult result, string propertyName)
86 | {
87 | if (!result.Properties.Contains(propertyName))
88 | {
89 | return null;
90 | }
91 |
92 | return result.Properties[Directory.AttrMsMcsAdmPwd][0]?.ToString();
93 | }
94 | }
95 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Internal/RateLimiter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.DirectoryServices.AccountManagement;
3 | using System.Web;
4 | using System.Web.Caching;
5 | using Lithnet.Laps.Web.App_LocalResources;
6 | using Lithnet.Laps.Web.Models;
7 |
8 | namespace Lithnet.Laps.Web
9 | {
10 | internal static class RateLimiter
11 | {
12 | public static bool IsRateLimitExceeded(LapRequestModel model, UserPrincipal p, HttpRequestBase r)
13 | {
14 | if (LapsConfigSection.Configuration.RateLimitIP.Enabled)
15 | {
16 | if (RateLimiter.IsIpThresholdExceeded(model, p, r, LapsConfigSection.Configuration.RateLimitIP.ReqPerMinute, 60)
17 | || RateLimiter.IsIpThresholdExceeded(model, p, r, LapsConfigSection.Configuration.RateLimitIP.ReqPerHour, 3600)
18 | || RateLimiter.IsIpThresholdExceeded(model, p, r, LapsConfigSection.Configuration.RateLimitIP.ReqPerDay, 86400))
19 | {
20 | return true;
21 | }
22 | }
23 |
24 | if (LapsConfigSection.Configuration.RateLimitUser.Enabled)
25 | {
26 | if (RateLimiter.IsUserThresholdExceeded(model, p, r, LapsConfigSection.Configuration.RateLimitUser.ReqPerMinute, 60)
27 | || RateLimiter.IsUserThresholdExceeded(model, p, r, LapsConfigSection.Configuration.RateLimitUser.ReqPerHour, 3600)
28 | || RateLimiter.IsUserThresholdExceeded(model, p, r, LapsConfigSection.Configuration.RateLimitUser.ReqPerDay, 86400))
29 | {
30 | return true;
31 | }
32 | }
33 | return false;
34 | }
35 |
36 | private static bool IsIpThresholdExceeded(LapRequestModel model, UserPrincipal p, HttpRequestBase r, int threshold, int duration)
37 | {
38 | if (RateLimiter.IsThresholdExceeded(r, threshold, duration))
39 | {
40 | Reporting.PerformAuditFailureActions(model, UIMessages.RateLimitError, EventIDs.RateLimitExceededIP,
41 | string.Format(LogMessages.RateLimitExceededIP, p.SamAccountName, r.UserHostAddress, threshold, duration), null, null, null, p, null);
42 | return true;
43 | }
44 |
45 | return false;
46 | }
47 |
48 | private static bool IsUserThresholdExceeded(LapRequestModel model, UserPrincipal p, HttpRequestBase r, int threshold, int duration)
49 | {
50 | if (RateLimiter.IsThresholdExceeded(p, threshold, duration))
51 | {
52 | Reporting.PerformAuditFailureActions(model, UIMessages.RateLimitError, EventIDs.RateLimitExceededUser,
53 | string.Format(LogMessages.RateLimitExceededUser, p.SamAccountName, r.UserHostAddress, threshold, duration), null, null, null, p, null);
54 | return true;
55 | }
56 |
57 | return false;
58 | }
59 |
60 | private static bool IsThresholdExceeded(HttpRequestBase r, int threshold, int duration)
61 | {
62 | string key1 = string.Join(@"-", duration, threshold, LapsConfigSection.Configuration.RateLimitIP.ThrottleOnXffIP ? r.GetUnmaskedIP() : r.UserHostAddress);
63 |
64 | return IsThresholdExceeded(key1, threshold, duration);
65 | }
66 |
67 | private static bool IsThresholdExceeded(UserPrincipal p, int threshold, int duration)
68 | {
69 | string key1 = string.Join(@"-", duration, threshold, p.Sid);
70 |
71 | return IsThresholdExceeded(key1, threshold, duration);
72 | }
73 |
74 | private static bool IsThresholdExceeded(string key, int threshold, int duration)
75 | {
76 | int count = 1;
77 |
78 | if (HttpRuntime.Cache[key] != null)
79 | {
80 | count = (int)HttpRuntime.Cache[key] + 1;
81 | }
82 |
83 | HttpRuntime.Cache.Insert(
84 | key,
85 | count,
86 | null,
87 | DateTime.UtcNow.AddSeconds(duration),
88 | Cache.NoSlidingExpiration,
89 | CacheItemPriority.Low,
90 | null
91 | );
92 |
93 | return count > threshold;
94 | }
95 | }
96 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Lithnet.Laps.Web.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | Yes
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Models/LapEntryModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.Linq;
5 | using System.Web;
6 |
7 | namespace Lithnet.Laps.Web.Models
8 | {
9 | public class LapEntryModel
10 | {
11 | [Required]
12 | public string ComputerName { get; set; }
13 |
14 | public string Password { get; set; }
15 |
16 | public string HtmlPassword { get; set; }
17 |
18 | public DateTime? ValidUntil { get; set; }
19 |
20 | public string FailureReason { get; set; }
21 | }
22 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Models/LapRequestModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.ComponentModel.DataAnnotations;
5 | using System.Linq;
6 | using System.Web;
7 | using Lithnet.Laps.Web.App_LocalResources;
8 |
9 | namespace Lithnet.Laps.Web.Models
10 | {
11 | [Localizable(true)]
12 | public class LapRequestModel
13 | {
14 | [Required(ErrorMessageResourceType = typeof(UIMessages), ErrorMessageResourceName = "ComputerNameIsRequired")]
15 | public string ComputerName { get; set; }
16 |
17 | public string FailureReason { get; set; }
18 | }
19 | }
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Lithnet.Laps.Web")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Lithnet.Laps.Web")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("d32d2723-5997-4d89-a31e-bc583df24da7")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Revision and Build Numbers
33 | // by using the '*' as shown below:
34 | [assembly: AssemblyVersion("1.0.*")]
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Properties/PublishProfiles/FolderProfile.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | FileSystem
9 | FileSystem
10 | Release
11 | Any CPU
12 |
13 | True
14 | False
15 | bin\Release\Publish
16 | True
17 | True
18 | True
19 | False
20 | DonotMerge
21 |
22 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Properties/PublishProfiles/Publish to local IIS.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | MSDeploy
9 | Release
10 | Any CPU
11 |
12 | True
13 | False
14 | localhost
15 | laps-test
16 |
17 | True
18 | InProc
19 | False
20 |
21 | <_SavePWD>False
22 |
23 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Scripts/clipboard.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * clipboard.js v2.0.0
3 | * https://zenorocha.github.io/clipboard.js
4 | *
5 | * Licensed MIT © Zeno Rocha
6 | */
7 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var n={};return e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,o){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:o})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=3)}([function(t,e,n){var o,r,i;!function(a,c){r=[t,n(7)],o=c,void 0!==(i="function"==typeof o?o.apply(e,r):o)&&(t.exports=i)}(0,function(t,e){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var o=function(t){return t&&t.__esModule?t:{default:t}}(e),r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.container=t.container,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var t=this,e="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[e?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=(0,o.default)(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=(0,o.default)(this.target),this.copyText()}},{key:"copyText",value:function(){var t=void 0;try{t=document.execCommand(this.action)}catch(e){t=!1}this.handleResult(t)}},{key:"handleResult",value:function(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(t){if(void 0!==t){if(!t||"object"!==(void 0===t?"undefined":r(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function(){return this._target}}]),t}();t.exports=a})},function(t,e,n){function o(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!c.string(e))throw new TypeError("Second argument must be a String");if(!c.fn(n))throw new TypeError("Third argument must be a Function");if(c.node(t))return r(t,e,n);if(c.nodeList(t))return i(t,e,n);if(c.string(t))return a(t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function r(t,e,n){return t.addEventListener(e,n),{destroy:function(){t.removeEventListener(e,n)}}}function i(t,e,n){return Array.prototype.forEach.call(t,function(t){t.addEventListener(e,n)}),{destroy:function(){Array.prototype.forEach.call(t,function(t){t.removeEventListener(e,n)})}}}function a(t,e,n){return u(document.body,t,e,n)}var c=n(6),u=n(5);t.exports=o},function(t,e){function n(){}n.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){function o(){r.off(t,o),e.apply(n,arguments)}var r=this;return o._=e,this.on(t,o,n)},emit:function(t){var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;for(o;o0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===d(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=(0,f.default)(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new l.default({action:this.action(e),target:this.target(e),text:this.text(e),container:this.container,trigger:e,emitter:this})}},{key:"defaultAction",value:function(t){return u("action",t)}},{key:"defaultTarget",value:function(t){var e=u("target",t);if(e)return document.querySelector(e)}},{key:"defaultText",value:function(t){return u("text",t)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["copy","cut"],e="string"==typeof t?[t]:t,n=!!document.queryCommandSupported;return e.forEach(function(t){n=n&&!!document.queryCommandSupported(t)}),n}}]),e}(s.default);t.exports=p})},function(t,e){function n(t,e){for(;t&&t.nodeType!==o;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}var o=9;if("undefined"!=typeof Element&&!Element.prototype.matches){var r=Element.prototype;r.matches=r.matchesSelector||r.mozMatchesSelector||r.msMatchesSelector||r.oMatchesSelector||r.webkitMatchesSelector}t.exports=n},function(t,e,n){function o(t,e,n,o,r){var a=i.apply(this,arguments);return t.addEventListener(n,a,r),{destroy:function(){t.removeEventListener(n,a,r)}}}function r(t,e,n,r,i){return"function"==typeof t.addEventListener?o.apply(null,arguments):"function"==typeof n?o.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return o(t,e,n,r,i)}))}function i(t,e,n,o){return function(n){n.delegateTarget=a(n.target,e),n.delegateTarget&&o.call(t,n)}}var a=n(4);t.exports=r},function(t,e){e.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},e.nodeList=function(t){var n=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===n||"[object HTMLCollection]"===n)&&"length"in t&&(0===t.length||e.node(t[0]))},e.string=function(t){return"string"==typeof t||t instanceof String},e.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},function(t,e){function n(t){var e;if("SELECT"===t.nodeName)t.focus(),e=t.value;else if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName){var n=t.hasAttribute("readonly");n||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),n||t.removeAttribute("readonly"),e=t.value}else{t.hasAttribute("contenteditable")&&t.focus();var o=window.getSelection(),r=document.createRange();r.selectNodeContents(t),o.removeAllRanges(),o.addRange(r),e=o.toString()}return e}t.exports=n}])});
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Scripts/esm/popper-utils.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) Federico Zivolo 2018
3 | Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT).
4 | */function a(a,b){if(1!==a.nodeType)return[];var c=getComputedStyle(a,null);return b?c[b]:c}function b(a){return'HTML'===a.nodeName?a:a.parentNode||a.host}function c(d){if(!d)return document.body;switch(d.nodeName){case'HTML':case'BODY':return d.ownerDocument.body;case'#document':return d.body;}var e=a(d),f=e.overflow,g=e.overflowX,h=e.overflowY;return /(auto|scroll|overlay)/.test(f+h+g)?d:c(b(d))}var d={},e=function(){var a=0=c.clientWidth&&d>=c.clientHeight}),k=0, ggray , rhysd , joscha , seckardt , marcfallows
4 |
5 | // This file only declares the public portions of the API.
6 | // It should not define internal pieces such as utils or modifier details.
7 |
8 | export type Position = 'top' | 'right' | 'bottom' | 'left';
9 |
10 | export type Placement = 'auto-start'
11 | | 'auto'
12 | | 'auto-end'
13 | | 'top-start'
14 | | 'top'
15 | | 'top-end'
16 | | 'right-start'
17 | | 'right'
18 | | 'right-end'
19 | | 'bottom-end'
20 | | 'bottom'
21 | | 'bottom-start'
22 | | 'left-end'
23 | | 'left'
24 | | 'left-start';
25 |
26 | export type Boundary = 'scrollParent' | 'viewport' | 'window';
27 |
28 | export type Behavior = 'flip' | 'clockwise' | 'counterclockwise';
29 |
30 | export type ModifierFn = (data: Data, options: Object) => Data;
31 |
32 | export interface BaseModifier {
33 | order?: number;
34 | enabled?: boolean;
35 | fn?: ModifierFn;
36 | }
37 |
38 | export interface Modifiers {
39 | shift?: BaseModifier;
40 | offset?: BaseModifier & {
41 | offset?: number | string,
42 | };
43 | preventOverflow?: BaseModifier & {
44 | priority?: Position[],
45 | padding?: number,
46 | boundariesElement?: Boundary | Element,
47 | escapeWithReference?: boolean
48 | };
49 | keepTogether?: BaseModifier;
50 | arrow?: BaseModifier & {
51 | element?: string | Element,
52 | };
53 | flip?: BaseModifier & {
54 | behavior?: Behavior | Position[],
55 | padding?: number,
56 | boundariesElement?: Boundary | Element,
57 | };
58 | inner?: BaseModifier;
59 | hide?: BaseModifier;
60 | applyStyle?: BaseModifier & {
61 | onLoad?: Function,
62 | gpuAcceleration?: boolean,
63 | };
64 | computeStyle?: BaseModifier & {
65 | gpuAcceleration?: boolean;
66 | x?: 'bottom' | 'top',
67 | y?: 'left' | 'right'
68 | };
69 |
70 | [name: string]: (BaseModifier & Record) | undefined;
71 | }
72 |
73 | export interface Offset {
74 | top: number;
75 | left: number;
76 | width: number;
77 | height: number;
78 | }
79 |
80 | export interface Data {
81 | instance: Popper;
82 | placement: Placement;
83 | originalPlacement: Placement;
84 | flipped: boolean;
85 | hide: boolean;
86 | arrowElement: Element;
87 | styles: CSSStyleDeclaration;
88 | boundaries: Object;
89 | offsets: {
90 | popper: Offset,
91 | reference: Offset,
92 | arrow: {
93 | top: number,
94 | left: number,
95 | },
96 | };
97 | }
98 |
99 | export interface PopperOptions {
100 | placement?: Placement;
101 | positionFixed?: boolean;
102 | eventsEnabled?: boolean;
103 | modifiers?: Modifiers;
104 | removeOnDestroy?: boolean;
105 |
106 | onCreate?(data: Data): void;
107 |
108 | onUpdate?(data: Data): void;
109 | }
110 |
111 | export interface ReferenceObject {
112 | clientHeight: number;
113 | clientWidth: number;
114 |
115 | getBoundingClientRect(): ClientRect;
116 | }
117 |
118 | declare class Popper {
119 | static modifiers: (BaseModifier & { name: string })[];
120 | static placements: Placement[];
121 | static Defaults: PopperOptions;
122 |
123 | options: PopperOptions;
124 |
125 | constructor(reference: Element | ReferenceObject, popper: Element, options?: PopperOptions);
126 |
127 | destroy(): void;
128 |
129 | update(): void;
130 |
131 | scheduleUpdate(): void;
132 |
133 | enableEventListeners(): void;
134 |
135 | disableEventListeners(): void;
136 | }
137 |
138 | export default Popper;
139 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Scripts/init-clip.js:
--------------------------------------------------------------------------------
1 | new ClipboardJS('#copy-button');
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Scripts/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | /* NUGET: BEGIN LICENSE TEXT
2 | *
3 | * Microsoft grants you the right to use these script files for the sole
4 | * purpose of either: (i) interacting through your browser with the Microsoft
5 | * website or online service, subject to the applicable licensing or use
6 | * terms; or (ii) using the files as included with a Microsoft product subject
7 | * to that product's license terms. Microsoft reserves all other rights to the
8 | * files not expressly granted by Microsoft, whether by implication, estoppel
9 | * or otherwise. Insofar as a script file is dual licensed under GPL,
10 | * Microsoft neither took the code under GPL nor distributes it thereunder but
11 | * under the terms set out in this paragraph. All notices and licenses
12 | * below are for informational purposes only.
13 | *
14 | * NUGET: END LICENSE TEXT */
15 | /* NUGET: BEGIN LICENSE TEXT
16 | *
17 | * Microsoft grants you the right to use these script files for the sole
18 | * purpose of either: (i) interacting through your browser with the Microsoft
19 | * website or online service, subject to the applicable licensing or use
20 | * terms; or (ii) using the files as included with a Microsoft product subject
21 | * to that product's license terms. Microsoft reserves all other rights to the
22 | * files not expressly granted by Microsoft, whether by implication, estoppel
23 | * or otherwise. Insofar as a script file is dual licensed under GPL,
24 | * Microsoft neither took the code under GPL nor distributes it thereunder but
25 | * under the terms set out in this paragraph. All notices and licenses
26 | * below are for informational purposes only.
27 | *
28 | * NUGET: END LICENSE TEXT */
29 | /*
30 | ** Unobtrusive validation support library for jQuery and jQuery Validate
31 | ** Copyright (C) Microsoft Corporation. All rights reserved.
32 | */
33 | (function(a){var d=a.validator,b,e="unobtrusiveValidation";function c(a,b,c){a.rules[b]=c;if(a.message)a.messages[b]=a.message}function j(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function f(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function h(a){return a.substr(0,a.lastIndexOf(".")+1)}function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a}function m(c,e){var b=a(this).find("[data-valmsg-for='"+f(e[0].name)+"']"),d=b.attr("data-valmsg-replace"),g=d?a.parseJSON(d)!==false:null;b.removeClass("field-validation-valid").addClass("field-validation-error");c.data("unobtrusiveContainer",b);if(g){b.empty();c.removeClass("input-validation-error").appendTo(b)}else c.hide()}function l(e,d){var c=a(this).find("[data-valmsg-summary=true]"),b=c.find("ul");if(b&&b.length&&d.errorList.length){b.empty();c.addClass("validation-summary-errors").removeClass("validation-summary-valid");a.each(d.errorList,function(){a(" ").html(this.message).appendTo(b)})}}function k(d){var b=d.data("unobtrusiveContainer"),c=b.attr("data-valmsg-replace"),e=c?a.parseJSON(c):null;if(b){b.addClass("field-validation-valid").removeClass("field-validation-error");d.removeData("unobtrusiveContainer");e&&b.empty()}}function n(){var b=a(this),c="__jquery_unobtrusive_validation_form_reset";if(b.data(c))return;b.data(c,true);try{b.data("validator").resetForm()}finally{b.removeData(c)}b.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors");b.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}function i(b){var c=a(b),f=c.data(e),i=a.proxy(n,b),g=d.unobtrusive.options||{},h=function(e,d){var c=g[e];c&&a.isFunction(c)&&c.apply(b,d)};if(!f){f={options:{errorClass:g.errorClass||"input-validation-error",errorElement:g.errorElement||"span",errorPlacement:function(){m.apply(b,arguments);h("errorPlacement",arguments)},invalidHandler:function(){l.apply(b,arguments);h("invalidHandler",arguments)},messages:{},rules:{},success:function(){k.apply(b,arguments);h("success",arguments)}},attachValidation:function(){c.off("reset."+e,i).on("reset."+e,i).validate(this.options)},validate:function(){c.validate();return c.valid()}};c.data(e,f)}return f}d.unobtrusive={adapters:[],parseElement:function(b,h){var d=a(b),f=d.parents("form")[0],c,e,g;if(!f)return;c=i(f);c.options.rules[b.name]=e={};c.options.messages[b.name]=g={};a.each(this.adapters,function(){var c="data-val-"+this.name,i=d.attr(c),h={};if(i!==undefined){c+="-";a.each(this.params,function(){h[this]=d.attr(c+this)});this.adapt({element:b,form:f,message:i,params:h,rules:e,messages:g})}});a.extend(e,{__dummy__:true});!h&&c.attachValidation()},parse:function(c){var b=a(c),e=b.parents().addBack().filter("form").add(b.find("form")).has("[data-val=true]");b.find("[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});e.each(function(){var a=i(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});d.addMethod("nonalphamin",function(c,d,b){var a;if(b){a=c.match(/\W/g);a=a&&a.length>=b}return a});if(d.methods.extension){b.addSingleVal("accept","mimtype");b.addSingleVal("extension","extension")}else b.addSingleVal("extension","extension","accept");b.addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength");b.add("equalto",["other"],function(b){var i=h(b.element.name),j=b.params.other,d=g(j,i),e=a(b.form).find(":input").filter("[name='"+f(d)+"']")[0];c(b,"equalTo",e)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},e=h(b.element.name);a.each(j(b.params.additionalfields||b.element.name),function(i,h){var c=g(h,e);d.data[c]=function(){var d=a(b.form).find(":input").filter("[name='"+f(c)+"']");return d.is(":checkbox")?d.filter(":checked").val()||d.filter(":hidden").val()||"":d.is(":radio")?d.filter(":checked").val()||"":d.val()}});c(b,"remote",d)});b.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&c(a,"minlength",a.params.min);a.params.nonalphamin&&c(a,"nonalphamin",a.params.nonalphamin);a.params.regex&&c(a,"regex",a.params.regex)});a(function(){d.unobtrusive.parse(document)})})(jQuery);
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Scripts/popper-utils.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) Federico Zivolo 2018
3 | Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT).
4 | */function a(a,b){if(1!==a.nodeType)return[];const c=getComputedStyle(a,null);return b?c[b]:c}function b(a){return'HTML'===a.nodeName?a:a.parentNode||a.host}function c(d){if(!d)return document.body;switch(d.nodeName){case'HTML':case'BODY':return d.ownerDocument.body;case'#document':return d.body;}const{overflow:e,overflowX:f,overflowY:g}=a(d);return /(auto|scroll|overlay)/.test(e+g+f)?d:c(b(d))}const d={};var e=function(a='all'){return(a=a.toString(),d.hasOwnProperty(a))?d[a]:('11'===a?d[a]=-1!==navigator.userAgent.indexOf('Trident'):'10'===a?d[a]=-1!==navigator.appVersion.indexOf('MSIE 10'):'all'===a?d[a]=-1!==navigator.userAgent.indexOf('Trident')||-1!==navigator.userAgent.indexOf('MSIE'):void 0,d.all=d.all||Object.keys(d).some((a)=>d[a]),d[a])};function f(b){if(!b)return document.documentElement;const c=e(10)?document.body:null;let d=b.offsetParent;for(;d===c&&b.nextElementSibling;)d=(b=b.nextElementSibling).offsetParent;const g=d&&d.nodeName;return g&&'BODY'!==g&&'HTML'!==g?-1!==['TD','TABLE'].indexOf(d.nodeName)&&'static'===a(d,'position')?f(d):d:b?b.ownerDocument.documentElement:document.documentElement}function g(a){const{nodeName:b}=a;return'BODY'!==b&&('HTML'===b||f(a.firstElementChild)===a)}function h(a){return null===a.parentNode?a:h(a.parentNode)}function i(a,b){if(!a||!a.nodeType||!b||!b.nodeType)return document.documentElement;const c=a.compareDocumentPosition(b)&Node.DOCUMENT_POSITION_FOLLOWING,d=c?a:b,e=c?b:a,j=document.createRange();j.setStart(d,0),j.setEnd(e,0);const{commonAncestorContainer:k}=j;if(a!==k&&b!==k||d.contains(e))return g(k)?k:f(k);const l=h(a);return l.host?i(l.host,b):i(a,h(b).host)}function j(a,b='top'){const c='top'===b?'scrollTop':'scrollLeft',d=a.nodeName;if('BODY'===d||'HTML'===d){const b=a.ownerDocument.documentElement,d=a.ownerDocument.scrollingElement||b;return d[c]}return a[c]}function k(a,b,c=!1){const d=j(b,'top'),e=j(b,'left'),f=c?-1:1;return a.top+=d*f,a.bottom+=d*f,a.left+=e*f,a.right+=e*f,a}function l(a,b){const c='x'===b?'Left':'Top',d='Left'==c?'Right':'Bottom';return parseFloat(a[`border${c}Width`],10)+parseFloat(a[`border${d}Width`],10)}function m(a,b,c,d){return Math.max(b[`offset${a}`],b[`scroll${a}`],c[`client${a}`],c[`offset${a}`],c[`scroll${a}`],e(10)?c[`offset${a}`]+d[`margin${'Height'===a?'Top':'Left'}`]+d[`margin${'Height'===a?'Bottom':'Right'}`]:0)}function n(){const a=document.body,b=document.documentElement,c=e(10)&&getComputedStyle(b);return{height:m('Height',a,b,c),width:m('Width',a,b,c)}}var o=Object.assign||function(a){for(var b,c=1;co({key:a},h[a],{area:w(h[a])})).sort((c,a)=>a.area-c.area),j=i.filter(({width:a,height:b})=>a>=c.clientWidth&&b>=c.clientHeight),k=0{b||(b=!0,window.Promise.resolve().then(()=>{b=!1,a()}))}}function C(a){let b=!1;return()=>{b||(b=!0,setTimeout(()=>{b=!1,a()},A))}}const D=y&&window.Promise;var E=D?B:C;function F(a,b){return Array.prototype.find?a.find(b):a.filter(b)[0]}function G(a,b,c){if(Array.prototype.findIndex)return a.findIndex((a)=>a[b]===c);const d=F(a,(a)=>a[b]===c);return a.indexOf(d)}function H(a){let b;if('HTML'===a.nodeName){const{width:a,height:c}=n();b={width:a,height:c,left:0,top:0}}else b={width:a.offsetWidth,height:a.offsetHeight,left:a.offsetLeft,top:a.offsetTop};return p(b)}function I(a){const b=getComputedStyle(a),c=parseFloat(b.marginTop)+parseFloat(b.marginBottom),d=parseFloat(b.marginLeft)+parseFloat(b.marginRight),e={width:a.offsetWidth+d,height:a.offsetHeight+c};return e}function J(a){const b={left:'right',right:'left',bottom:'top',top:'bottom'};return a.replace(/left|right|bottom|top/g,(a)=>b[a])}function K(a,b,c){c=c.split('-')[0];const d=I(a),e={width:d.width,height:d.height},f=-1!==['right','left'].indexOf(c),g=f?'top':'left',h=f?'left':'top',i=f?'height':'width',j=f?'width':'height';return e[g]=b[g]+b[i]/2-d[i]/2,e[h]=c===h?b[h]-d[j]:b[J(h)],e}function L(a,b,c,d=null){const e=d?u(b):i(b,c);return r(c,e,d)}function M(a){const b=[!1,'ms','Webkit','Moz','O'],c=a.charAt(0).toUpperCase()+a.slice(1);for(let d=0;dc&&a===b)}function P(a,b,c){const d=F(a,({name:a})=>a===b),e=!!d&&a.some((a)=>a.name===c&&a.enabled&&a.order{a.removeEventListener('scroll',b.updateBound)}),b.updateBound=null,b.scrollParents=[],b.scrollElement=null,b.eventsEnabled=!1,b}function T(a,b,c){const d=void 0===c?a:a.slice(0,G(a,'name',c));return d.forEach((a)=>{a['function']&&console.warn('`modifier.function` is deprecated, use `modifier.fn`!');const c=a['function']||a.fn;a.enabled&&N(c)&&(b.offsets.popper=p(b.offsets.popper),b.offsets.reference=p(b.offsets.reference),b=c(b,a))}),b}function U(a,b){Object.keys(b).forEach(function(c){const d=b[c];!1===d?a.removeAttribute(c):a.setAttribute(c,b[c])})}function V(a,b){Object.keys(b).forEach((c)=>{let d='';-1!==['width','height','top','right','bottom','left'].indexOf(c)&&Q(b[c])&&(d='px'),a.style[c]=b[c]+d})}function W(a,b,d,e){const f='BODY'===a.nodeName,g=f?a.ownerDocument.defaultView:a;g.addEventListener(b,d,{passive:!0}),f||W(c(g.parentNode),b,d,e),e.push(g)}function X(a,b,d,e){d.updateBound=e,R(a).addEventListener('resize',d.updateBound,{passive:!0});const f=c(a);return W(f,'scroll',d.updateBound,d.scrollParents),d.scrollElement=f,d.eventsEnabled=!0,d}var Y={computeAutoPlacement:x,debounce:E,findIndex:G,getBordersSize:l,getBoundaries:v,getBoundingClientRect:q,getClientRect:p,getOffsetParent:f,getOffsetRect:H,getOffsetRectRelativeToArbitraryNode:r,getOuterSizes:I,getParentNode:b,getPopperOffsets:K,getReferenceOffsets:L,getScroll:j,getScrollParent:c,getStyleComputedProperty:a,getSupportedPropertyName:M,getWindowSizes:n,isFixed:t,isFunction:N,isModifierEnabled:O,isModifierRequired:P,isNumeric:Q,removeEventListeners:S,runModifiers:T,setAttributes:U,setStyles:V,setupEventListeners:X};export{x as computeAutoPlacement,E as debounce,G as findIndex,l as getBordersSize,v as getBoundaries,q as getBoundingClientRect,p as getClientRect,f as getOffsetParent,H as getOffsetRect,r as getOffsetRectRelativeToArbitraryNode,I as getOuterSizes,b as getParentNode,K as getPopperOffsets,L as getReferenceOffsets,j as getScroll,c as getScrollParent,a as getStyleComputedProperty,M as getSupportedPropertyName,n as getWindowSizes,t as isFixed,N as isFunction,O as isModifierEnabled,P as isModifierRequired,Q as isNumeric,S as removeEventListeners,T as runModifiers,U as setAttributes,V as setStyles,X as setupEventListeners};export default Y;
5 | //# sourceMappingURL=popper-utils.min.js.map
6 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Scripts/umd/popper-utils.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) Federico Zivolo 2018
3 | Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT).
4 | */(function(a,b){'object'==typeof exports&&'undefined'!=typeof module?b(exports):'function'==typeof define&&define.amd?define(['exports'],b):b(a.PopperUtils={})})(this,function(a){'use strict';function b(a,b){if(1!==a.nodeType)return[];var c=getComputedStyle(a,null);return b?c[b]:c}function c(a){return'HTML'===a.nodeName?a:a.parentNode||a.host}function d(a){if(!a)return document.body;switch(a.nodeName){case'HTML':case'BODY':return a.ownerDocument.body;case'#document':return a.body;}var e=b(a),f=e.overflow,g=e.overflowX,h=e.overflowY;return /(auto|scroll|overlay)/.test(f+h+g)?a:d(c(a))}function e(a){if(!a)return document.documentElement;for(var c=S(10)?document.body:null,d=a.offsetParent;d===c&&a.nextElementSibling;)d=(a=a.nextElementSibling).offsetParent;var f=d&&d.nodeName;return f&&'BODY'!==f&&'HTML'!==f?-1!==['TD','TABLE'].indexOf(d.nodeName)&&'static'===b(d,'position')?e(d):d:a?a.ownerDocument.documentElement:document.documentElement}function f(a){var b=a.nodeName;return'BODY'!==b&&('HTML'===b||e(a.firstElementChild)===a)}function g(a){return null===a.parentNode?a:g(a.parentNode)}function h(a,b){if(!a||!a.nodeType||!b||!b.nodeType)return document.documentElement;var c=a.compareDocumentPosition(b)&Node.DOCUMENT_POSITION_FOLLOWING,d=c?a:b,i=c?b:a,j=document.createRange();j.setStart(d,0),j.setEnd(i,0);var k=j.commonAncestorContainer;if(a!==k&&b!==k||d.contains(i))return f(k)?k:e(k);var l=g(a);return l.host?h(l.host,b):h(a,g(b).host)}function j(a){var b=1=c.clientWidth&&d>=c.clientHeight}),k=0
7 |
8 |
9 |
10 | @UIMessages.AuthNError
11 |
12 |
13 |
14 | @Request.Params["message"]
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Views/Home/Index.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = "Home Page";
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Views/Home/LogOut.cshtml:
--------------------------------------------------------------------------------
1 | @using System.Configuration
2 | @{
3 | ViewBag.Title = "Logged out";
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Views/Lap/Get.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = "Request Password";
3 | }
4 |
5 | @model Lithnet.Laps.Web.Models.LapRequestModel
6 |
7 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Views/Lap/RateLimitExceeded.cshtml:
--------------------------------------------------------------------------------
1 | @using System.Configuration
2 | @{
3 | ViewBag.Title = "Too many requests";
4 | }
5 |
6 |
7 |
8 |
9 |
10 | @UIMessages.RateLimitError
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Views/Lap/Show.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = "Password";
3 | }
4 |
5 | @model Lithnet.Laps.Web.Models.LapEntryModel
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Views/Shared/Error.cshtml:
--------------------------------------------------------------------------------
1 | @using System.Configuration
2 | @{
3 | ViewBag.Title = "Error";
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Views/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 | @using System.Configuration
2 |
3 |
4 |
5 |
6 |
7 | @ConfigurationManager.AppSettings["app:Title"]
8 | @Styles.Render("~/Content/css")
9 |
10 |
11 |
12 |
13 |
14 |
18 | @RenderBody()
19 |
20 | @if (MvcApplication.CanLogout)
21 | {
22 |
25 | }
26 |
27 | @Scripts.Render("~/bundles/jquery")
28 | @Scripts.Render("~/bundles/bootstrap")
29 | @RenderSection("scripts", required: false)
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Views/Web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "~/Views/Shared/_Layout.cshtml";
3 | }
4 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Web.Debug.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Web.Release.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
19 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/Web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
46 |
47 |
48 |
49 |
50 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/clipboard.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * clipboard.js v2.0.0
3 | * https://zenorocha.github.io/clipboard.js
4 | *
5 | * Licensed MIT © Zeno Rocha
6 | */
7 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var n={};return e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,o){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:o})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=3)}([function(t,e,n){var o,r,i;!function(a,c){r=[t,n(7)],o=c,void 0!==(i="function"==typeof o?o.apply(e,r):o)&&(t.exports=i)}(0,function(t,e){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var o=function(t){return t&&t.__esModule?t:{default:t}}(e),r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.container=t.container,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var t=this,e="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[e?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=(0,o.default)(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=(0,o.default)(this.target),this.copyText()}},{key:"copyText",value:function(){var t=void 0;try{t=document.execCommand(this.action)}catch(e){t=!1}this.handleResult(t)}},{key:"handleResult",value:function(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(t){if(void 0!==t){if(!t||"object"!==(void 0===t?"undefined":r(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function(){return this._target}}]),t}();t.exports=a})},function(t,e,n){function o(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!c.string(e))throw new TypeError("Second argument must be a String");if(!c.fn(n))throw new TypeError("Third argument must be a Function");if(c.node(t))return r(t,e,n);if(c.nodeList(t))return i(t,e,n);if(c.string(t))return a(t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function r(t,e,n){return t.addEventListener(e,n),{destroy:function(){t.removeEventListener(e,n)}}}function i(t,e,n){return Array.prototype.forEach.call(t,function(t){t.addEventListener(e,n)}),{destroy:function(){Array.prototype.forEach.call(t,function(t){t.removeEventListener(e,n)})}}}function a(t,e,n){return u(document.body,t,e,n)}var c=n(6),u=n(5);t.exports=o},function(t,e){function n(){}n.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){function o(){r.off(t,o),e.apply(n,arguments)}var r=this;return o._=e,this.on(t,o,n)},emit:function(t){var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;for(o;o0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===d(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=(0,f.default)(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new l.default({action:this.action(e),target:this.target(e),text:this.text(e),container:this.container,trigger:e,emitter:this})}},{key:"defaultAction",value:function(t){return u("action",t)}},{key:"defaultTarget",value:function(t){var e=u("target",t);if(e)return document.querySelector(e)}},{key:"defaultText",value:function(t){return u("text",t)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["copy","cut"],e="string"==typeof t?[t]:t,n=!!document.queryCommandSupported;return e.forEach(function(t){n=n&&!!document.queryCommandSupported(t)}),n}}]),e}(s.default);t.exports=p})},function(t,e){function n(t,e){for(;t&&t.nodeType!==o;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}var o=9;if("undefined"!=typeof Element&&!Element.prototype.matches){var r=Element.prototype;r.matches=r.matchesSelector||r.mozMatchesSelector||r.msMatchesSelector||r.oMatchesSelector||r.webkitMatchesSelector}t.exports=n},function(t,e,n){function o(t,e,n,o,r){var a=i.apply(this,arguments);return t.addEventListener(n,a,r),{destroy:function(){t.removeEventListener(n,a,r)}}}function r(t,e,n,r,i){return"function"==typeof t.addEventListener?o.apply(null,arguments):"function"==typeof n?o.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return o(t,e,n,r,i)}))}function i(t,e,n,o){return function(n){n.delegateTarget=a(n.target,e),n.delegateTarget&&o.call(t,n)}}var a=n(4);t.exports=r},function(t,e){e.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},e.nodeList=function(t){var n=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===n||"[object HTMLCollection]"===n)&&"length"in t&&(0===t.length||e.node(t[0]))},e.string=function(t){return"string"==typeof t||t instanceof String},e.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},function(t,e){function n(t){var e;if("SELECT"===t.nodeName)t.focus(),e=t.value;else if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName){var n=t.hasAttribute("readonly");n||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),n||t.removeAttribute("readonly"),e=t.value}else{t.hasAttribute("contenteditable")&&t.focus();var o=window.getSelection(),r=document.createRange();r.selectNodeContents(t),o.removeAllRanges(),o.addRange(r),e=o.toString()}return e}t.exports=n}])});
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/favicon.ico
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lithnet/laps-web/0e478beeee01cdf6b542d3900634a8c1a7c2446f/src/Lithnet.Laps.Web/Lithnet.Laps.Web/images/logo.png
--------------------------------------------------------------------------------
/src/Lithnet.Laps.Web/Lithnet.Laps.Web/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------