delete un-used code. (#218)

This commit is contained in:
Tingluo Huang
2019-12-16 17:05:26 -05:00
committed by GitHub
parent c3c66bb14a
commit d0a4a41a63
582 changed files with 155 additions and 66274 deletions

View File

@@ -1,92 +0,0 @@
using System;
using System.Linq;
using System.Net;
using GitHub.Services.Common.Internal;
namespace GitHub.Services.Common
{
/// <summary>
/// Provides a credential for basic authentication against a Visual Studio Service.
/// </summary>
public sealed class VssBasicCredential : FederatedCredential
{
/// <summary>
/// Initializes a new <c>VssBasicCredential</c> instance with no token specified.
/// </summary>
public VssBasicCredential()
: this((VssBasicToken)null)
{
}
/// <summary>
/// Initializes a new <c>VssBasicCredential</c> instance with the specified user name and password.
/// </summary>
/// <param name="userName">The user name</param>
/// <param name="password">The password</param>
public VssBasicCredential(
string userName,
string password)
: this(new VssBasicToken(new NetworkCredential(userName, password)))
{
}
/// <summary>
/// Initializes a new <c>VssBasicCredential</c> instance with the specified token.
/// </summary>
/// <param name="initialToken">An optional token which, if present, should be used before obtaining a new token</param>
public VssBasicCredential(ICredentials initialToken)
: this(new VssBasicToken(initialToken))
{
}
/// <summary>
/// Initializes a new <c>VssBasicCredential</c> instance with the specified token.
/// </summary>
/// <param name="initialToken">An optional token which, if present, should be used before obtaining a new token</param>
public VssBasicCredential(VssBasicToken initialToken)
: base(initialToken)
{
}
public override VssCredentialsType CredentialType
{
get
{
return VssCredentialsType.Basic;
}
}
public override bool IsAuthenticationChallenge(IHttpResponse webResponse)
{
if (webResponse == null)
{
return false;
}
if (webResponse.StatusCode != HttpStatusCode.Found &&
webResponse.StatusCode != HttpStatusCode.Redirect &&
webResponse.StatusCode != HttpStatusCode.Unauthorized)
{
return false;
}
return webResponse.Headers.GetValues(HttpHeaders.WwwAuthenticate).Any(x => x.StartsWith("Basic", StringComparison.OrdinalIgnoreCase));
}
protected override IssuedTokenProvider OnCreateTokenProvider(
Uri serverUrl,
IHttpResponse response)
{
if (serverUrl.Scheme != "https")
{
String unsafeBasicAuthEnv = Environment.GetEnvironmentVariable("VSS_ALLOW_UNSAFE_BASICAUTH") ?? "false";
if (!Boolean.TryParse(unsafeBasicAuthEnv, out Boolean unsafeBasicAuth) || !unsafeBasicAuth)
{
throw new InvalidOperationException(CommonResources.BasicAuthenticationRequiresSsl());
}
}
return new BasicAuthTokenProvider(this, serverUrl);
}
}
}

View File

@@ -1,63 +0,0 @@
using System;
using System.Globalization;
using System.Net;
namespace GitHub.Services.Common
{
/// <summary>
/// Provides a token for basic authentication of internet identities.
/// </summary>
public sealed class VssBasicToken : IssuedToken
{
/// <summary>
/// Initializes a new <c>BasicAuthToken</c> instance with the specified token value.
/// </summary>
/// <param name="credentials">The credentials which should be used for authentication</param>
public VssBasicToken(ICredentials credentials)
{
m_credentials = credentials;
}
internal ICredentials Credentials
{
get
{
return m_credentials;
}
}
protected internal override VssCredentialsType CredentialType
{
get
{
return VssCredentialsType.Basic;
}
}
internal override void ApplyTo(IHttpRequest request)
{
var basicCredential = m_credentials.GetCredential(request.RequestUri, "Basic");
if (basicCredential != null)
{
request.Headers.SetValue(Internal.HttpHeaders.Authorization, "Basic " + FormatBasicAuthHeader(basicCredential));
}
}
private static String FormatBasicAuthHeader(NetworkCredential credential)
{
String authHeader = String.Empty;
if (!String.IsNullOrEmpty(credential.Domain))
{
authHeader = String.Format(CultureInfo.InvariantCulture, "{0}\\{1}:{2}", credential.Domain, credential.UserName, credential.Password);
}
else
{
authHeader = String.Format(CultureInfo.InvariantCulture, "{0}:{1}", credential.UserName, credential.Password);
}
return Convert.ToBase64String(VssHttpRequestSettings.Encoding.GetBytes(authHeader));
}
private readonly ICredentials m_credentials;
}
}

View File

@@ -1,39 +0,0 @@
using System;
using System.Net;
namespace GitHub.Services.Common
{
internal sealed class BasicAuthTokenProvider : IssuedTokenProvider
{
public BasicAuthTokenProvider(
VssBasicCredential credential,
Uri serverUrl)
: base(credential, serverUrl, serverUrl)
{
}
protected override String AuthenticationScheme
{
get
{
return "Basic";
}
}
public new VssBasicCredential Credential
{
get
{
return (VssBasicCredential)base.Credential;
}
}
public override Boolean GetTokenIsInteractive
{
get
{
return base.CurrentToken == null;
}
}
}
}

View File

@@ -51,47 +51,7 @@ namespace GitHub.Services.Common
/// Initializes a new <c>VssCredentials</c> instance with default credentials.
/// </summary>
public VssCredentials()
: this(true)
{
}
/// <summary>
/// Initializes a new <c>VssCredentials</c> instance with default credentials if specified.
/// </summary>
/// <param name="useDefaultCredentials">True to use default windows credentials; otherwise, false</param>
public VssCredentials(bool useDefaultCredentials)
: this(new WindowsCredential(useDefaultCredentials))
{
}
/// <summary>
/// Initializes a new <c>VssCredentials</c> instance with the specified windows credential.
/// </summary>
/// <param name="windowsCredential">The windows credential to use for authentication</param>
public VssCredentials(WindowsCredential windowsCredential)
: this(windowsCredential, null)
{
}
/// <summary>
/// Initializes a new <c>VssCredentials</c> instance with the specified windows credential.
/// </summary>
/// <param name="windowsCredential">The windows credential to use for authentication</param>
/// <param name="promptType">CredentialPromptType.PromptIfNeeded if interactive prompts are allowed, otherwise CredentialProptType.DoNotPrompt</param>
public VssCredentials(
WindowsCredential windowsCredential,
CredentialPromptType promptType)
: this(windowsCredential, null, promptType)
{
}
/// <summary>
/// Initializes a new <c>VssCredentials</c> instance with the specified issued token credential and
/// default windows credential.
/// </summary>
/// <param name="federatedCredential">The federated credential to use for authentication</param>
public VssCredentials(FederatedCredential federatedCredential)
: this(new WindowsCredential(), federatedCredential)
: this(null)
{
}
@@ -99,12 +59,9 @@ namespace GitHub.Services.Common
/// Initializes a new <c>VssCredentials</c> instance with the specified windows and issued token
/// credential.
/// </summary>
/// <param name="windowsCredential">The windows credential to use for authentication</param>
/// <param name="federatedCredential">The federated credential to use for authentication</param>
public VssCredentials(
WindowsCredential windowsCredential,
FederatedCredential federatedCredential)
: this(windowsCredential, federatedCredential, EnvironmentUserInteractive
public VssCredentials(FederatedCredential federatedCredential)
: this(federatedCredential, EnvironmentUserInteractive
? CredentialPromptType.PromptIfNeeded : CredentialPromptType.DoNotPrompt)
{
}
@@ -113,14 +70,12 @@ namespace GitHub.Services.Common
/// Initializes a new <c>VssCredentials</c> instance with the specified windows and issued token
/// credential.
/// </summary>
/// <param name="windowsCredential">The windows credential to use for authentication</param>
/// <param name="federatedCredential">The federated credential to use for authentication</param>
/// <param name="promptType">CredentialPromptType.PromptIfNeeded if interactive prompts are allowed, otherwise CredentialProptType.DoNotPrompt</param>
public VssCredentials(
WindowsCredential windowsCredential,
FederatedCredential federatedCredential,
CredentialPromptType promptType)
: this(windowsCredential, federatedCredential, promptType, null)
: this(federatedCredential, promptType, null)
{
}
@@ -128,16 +83,14 @@ namespace GitHub.Services.Common
/// Initializes a new <c>VssCredentials</c> instance with the specified windows and issued token
/// credential.
/// </summary>
/// <param name="windowsCredential">The windows credential to use for authentication</param>
/// <param name="federatedCredential">The federated credential to use for authentication</param>
/// <param name="promptType">CredentialPromptType.PromptIfNeeded if interactive prompts are allowed; otherwise, CredentialProptType.DoNotPrompt</param>
/// <param name="scheduler">An optional <c>TaskScheduler</c> to ensure credentials prompting occurs on the UI thread</param>
public VssCredentials(
WindowsCredential windowsCredential,
FederatedCredential federatedCredential,
CredentialPromptType promptType,
TaskScheduler scheduler)
: this(windowsCredential, federatedCredential, promptType, scheduler, null)
: this(federatedCredential, promptType, scheduler, null)
{
}
@@ -145,13 +98,11 @@ namespace GitHub.Services.Common
/// Initializes a new <c>VssCredentials</c> instance with the specified windows and issued token
/// credential.
/// </summary>
/// <param name="windowsCredential">The windows credential to use for authentication</param>
/// <param name="federatedCredential">The federated credential to use for authentication</param>
/// <param name="promptType">CredentialPromptType.PromptIfNeeded if interactive prompts are allowed; otherwise, CredentialProptType.DoNotPrompt</param>
/// <param name="scheduler">An optional <c>TaskScheduler</c> to ensure credentials prompting occurs on the UI thread</param>
/// <param name="credentialPrompt">An optional <c>IVssCredentialPrompt</c> to perform prompting for credentials</param>
public VssCredentials(
WindowsCredential windowsCredential,
FederatedCredential federatedCredential,
CredentialPromptType promptType,
TaskScheduler scheduler,
@@ -172,13 +123,6 @@ namespace GitHub.Services.Common
scheduler = TaskScheduler.Default;
}
if (windowsCredential != null)
{
m_windowsCredential = windowsCredential;
m_windowsCredential.Scheduler = scheduler;
m_windowsCredential.Prompt = credentialPrompt;
}
if (federatedCredential != null)
{
m_federatedCredential = federatedCredential;
@@ -199,16 +143,6 @@ namespace GitHub.Services.Common
return new VssCredentials(credential);
}
/// <summary>
/// Implicitly converts a <c>WindowsCredential</c> instance into a <c>VssCredentials</c> instance.
/// </summary>
/// <param name="credential">The windows credential instance</param>
/// <returns>A new <c>VssCredentials</c> instance which wraps the specified credential</returns>
public static implicit operator VssCredentials(WindowsCredential credential)
{
return new VssCredentials(credential);
}
/// <summary>
/// Gets or sets a value indicating whether or not interactive prompts are allowed.
/// </summary>
@@ -240,17 +174,6 @@ namespace GitHub.Services.Common
}
}
/// <summary>
/// Gets the windows credential to use for NTLM authentication with the server.
/// </summary>
public WindowsCredential Windows
{
get
{
return m_windowsCredential;
}
}
/// <summary>
/// A pluggable credential store.
/// Simply assign a storage implementation to this property
@@ -267,11 +190,6 @@ namespace GitHub.Services.Common
{
m_credentialStorage = value;
if (m_windowsCredential != null)
{
m_windowsCredential.Storage = value;
}
if (m_federatedCredential != null)
{
m_federatedCredential.Storage = value;
@@ -327,20 +245,6 @@ namespace GitHub.Services.Common
VssHttpEventSource.Log.IssuedTokenProviderCreated(traceActivity, tokenProvider);
}
}
else if (m_windowsCredential != null && m_windowsCredential.IsAuthenticationChallenge(webResponse))
{
if (tokenProvider != null)
{
VssHttpEventSource.Log.IssuedTokenProviderRemoved(traceActivity, tokenProvider);
}
tokenProvider = m_windowsCredential.CreateTokenProvider(serverUrl, webResponse, failedToken);
if (tokenProvider != null)
{
VssHttpEventSource.Log.IssuedTokenProviderCreated(traceActivity, tokenProvider);
}
}
m_currentProvider = tokenProvider;
}
@@ -356,7 +260,7 @@ namespace GitHub.Services.Common
/// <param name="provider">Stores the active token provider, if one exists</param>
/// <returns>True if a token provider was found, false otherwise</returns>
public bool TryGetTokenProvider(
Uri serverUrl,
Uri serverUrl,
out IssuedTokenProvider provider)
{
ArgumentUtility.CheckForNull(serverUrl, "serverUrl");
@@ -371,11 +275,6 @@ namespace GitHub.Services.Common
m_currentProvider = m_federatedCredential.CreateTokenProvider(serverUrl, null, null);
}
if (m_currentProvider == null && m_windowsCredential != null)
{
m_currentProvider = m_windowsCredential.CreateTokenProvider(serverUrl, null, null);
}
if (m_currentProvider != null)
{
VssHttpEventSource.Log.IssuedTokenProviderCreated(VssTraceActivity.Current, m_currentProvider);
@@ -401,11 +300,6 @@ namespace GitHub.Services.Common
}
bool isChallenge = false;
if (m_windowsCredential != null)
{
isChallenge = m_windowsCredential.IsAuthenticationChallenge(webResponse);
}
if (!isChallenge && m_federatedCredential != null)
{
isChallenge = m_federatedCredential.IsAuthenticationChallenge(webResponse);
@@ -415,8 +309,8 @@ namespace GitHub.Services.Common
}
internal void SignOut(
Uri serverUrl,
Uri serviceLocation,
Uri serverUrl,
Uri serviceLocation,
string identityProvider)
{
// Remove the token in the storage and the current token provider. Note that we don't
@@ -450,110 +344,6 @@ namespace GitHub.Services.Common
tokenProviderWithSignOut.SignOut(serviceLocation, serverUrl, identityProvider);
}
#if !NETSTANDARD
/// <summary>
/// Loads stored credentials for the specified server if found. If no credentials are found in the windows
/// credential store for the specified server and options then default credentials are returned.
/// </summary>
/// <param name="serverUrl">The server location</param>
/// <param name="requireExactMatch">A value indicating whether or not an exact or partial match of the server is required</param>
/// <returns>A credentials object populated with stored credentials for the server if found</returns>
public static VssCredentials LoadCachedCredentials(
Uri serverUrl,
bool requireExactMatch)
{
return LoadCachedCredentials(null, serverUrl, requireExactMatch);
}
/// <summary>
/// Loads stored credentials for the specified server if found. If no credentials are found for the specified server and options then default credentials are returned.
/// This overload assumes that the credentials are to be stored under the TFS server's registry root
/// </summary>
/// <param name="featureRegistryKeyword">An optional application name for isolated credential storage in the registry</param>
/// <param name="serverUrl">The server location</param>
/// <param name="requireExactMatch">A value indicating whether or not an exact or partial match of the server is required</param>
/// <returns>A credentials object populated with stored credentials for the server if found</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public static VssCredentials LoadCachedCredentials(
string featureRegistryKeyword,
Uri serverUrl,
bool requireExactMatch)
{
ArgumentUtility.CheckForNull(serverUrl, "serverUrl");
bool uriKnownToCachedProvider = false;
VssCredentials cred = LoadCachedCredentialsFromRegisteredProviders(serverUrl, out uriKnownToCachedProvider);
// If one of the registered credential providers had the target URI in its cache but failed to return a valid credential it means
// we should have had a cred but something went wrong (user canceled, user failed, auth source unavailable, etc.). In that case
// we Do Not want to carry on with the fallback to the VS registry/windows store credential caches. Even if that worked to get a
// credential it would put the user in a bad state (having an active, authenticated connection with an unexpected credential type).
if (cred == null && !uriKnownToCachedProvider)
{
WindowsCredential windowsCredential = null;
FederatedCredential federatedCredential = null;
CredentialsCacheManager credentialsCacheManager = new CredentialsCacheManager();
TfsCredentialCacheEntry cacheEntry = credentialsCacheManager.GetCredentials(featureRegistryKeyword, serverUrl, requireExactMatch, null);
if (cacheEntry != null)
{
if (cacheEntry.NonInteractive)
{
switch (cacheEntry.Type)
{
case CachedCredentialsType.ServiceIdentity:
VssServiceIdentityToken initialToken = null;
string initialTokenValue = ReadAuthorizationToken(cacheEntry.Attributes);
if (!string.IsNullOrEmpty(initialTokenValue))
{
initialToken = new VssServiceIdentityToken(initialTokenValue);
}
// Initialize the issued token credential using the stored token if it exists
federatedCredential = new VssServiceIdentityCredential(cacheEntry.Credentials.UserName,
cacheEntry.Credentials.Password,
initialToken);
break;
case CachedCredentialsType.Windows:
windowsCredential = new WindowsCredential(cacheEntry.Credentials);
break;
}
}
}
cred = new VssCredentials(windowsCredential ?? new WindowsCredential(true), federatedCredential, CredentialPromptType.DoNotPrompt);
}
return cred ?? new VssCredentials(new WindowsCredential(true), null, CredentialPromptType.DoNotPrompt);
}
[EditorBrowsable(EditorBrowsableState.Never)]
public static VssCredentials LoadCachedCredentialsFromRegisteredProviders(Uri serverUri, out bool knownUri)
{
LoadRegisteredCachedVssCredentialProviders();
bool uriKnownByAnyProvider = false;
VssCredentials cred = null;
foreach (var pair in m_loadedCachedVssCredentialProviders)
{
bool uriKnownToProvider = false;
cred = pair.Value?.GetCachedCredentials(serverUri, out uriKnownToProvider);
if (cred != null || uriKnownToProvider)
{
uriKnownByAnyProvider |= uriKnownToProvider;
break;
}
}
knownUri = uriKnownByAnyProvider;
return cred;
}
private static void LoadRegisteredCachedVssCredentialProviders()
{
CredentialsProviderRegistryHelper.LoadCachedVssCredentialProviders(ref m_loadedCachedVssCredentialProviders);
}
private static ConcurrentDictionary<string, ICachedVssCredentialProvider> m_loadedCachedVssCredentialProviders = new ConcurrentDictionary<string, ICachedVssCredentialProvider>();
#endif
[EditorBrowsable(EditorBrowsableState.Never)]
public static void WriteAuthorizationToken(
string token,
@@ -604,7 +394,6 @@ namespace GitHub.Services.Common
private object m_thisLock;
private CredentialPromptType m_promptType;
private IssuedTokenProvider m_currentProvider;
protected WindowsCredential m_windowsCredential;
protected FederatedCredential m_federatedCredential;
private IVssCredentialStorage m_credentialStorage;
}

View File

@@ -1,164 +0,0 @@
using System;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
namespace GitHub.Services.Common
{
/// <summary>
/// Provides federated authentication as a service identity with a Visual Studio Service.
/// </summary>
[Serializable]
public sealed class VssServiceIdentityCredential : FederatedCredential
{
/// <summary>
/// Initializes a new <c>VssServiceIdentityCredential</c> instance with the specified user name and password.
/// </summary>
/// <param name="userName">The user name</param>
/// <param name="password">The password</param>
public VssServiceIdentityCredential(
string userName,
string password)
: this(userName, password, null)
{
}
/// <summary>
/// Initializes a new <c>VssServiceIdentityCredential</c> instance with the specified user name and password. The
/// provided token, if not null, will be used before attempting authentication with the credentials.
/// </summary>
/// <param name="userName">The user name</param>
/// <param name="password">The password</param>
/// <param name="initialToken">An optional token which, if present, should be used before obtaining a new token</param>
public VssServiceIdentityCredential(
string userName,
string password,
VssServiceIdentityToken initialToken)
: this(userName, password, initialToken, null)
{
}
/// <summary>
/// Initializes a new <c>VssServiceIdentityCredential</c> instance with the specified access token.
/// </summary>
/// <param name="token">A token which may be used for authorization as the desired service identity</param>
public VssServiceIdentityCredential(VssServiceIdentityToken token)
: this(null, null, token, null)
{
}
/// <summary>
/// Initializes a new <c>VssServiceIdentityCredential</c> instance with the specified user name and password. The
/// provided token, if not null, will be used before attempting authentication with the credentials.
/// </summary>
/// <param name="userName">The user name</param>
/// <param name="password">The password</param>
/// <param name="initialToken">An optional token which, if present, should be used before obtaining a new token</param>
/// <param name="innerHandler">An optional HttpMessageHandler which if passed will be passed along to the TokenProvider when executing OnCreateTokenProvider </param>
public VssServiceIdentityCredential(
string userName,
string password,
VssServiceIdentityToken initialToken,
DelegatingHandler innerHandler)
: base(initialToken)
{
m_userName = userName;
m_password = password;
m_innerHandler = innerHandler;
}
public override VssCredentialsType CredentialType
{
get
{
return VssCredentialsType.ServiceIdentity;
}
}
/// <summary>
/// Gets the user name.
/// </summary>
public String UserName
{
get
{
return m_userName;
}
}
/// <summary>
/// Gets the password.
/// </summary>
internal String Password
{
get
{
return m_password;
}
}
public override bool IsAuthenticationChallenge(IHttpResponse webResponse)
{
if (webResponse == null)
{
return false;
}
if (webResponse.StatusCode == HttpStatusCode.Found ||
webResponse.StatusCode == HttpStatusCode.Redirect ||
webResponse.StatusCode == HttpStatusCode.Unauthorized)
{
var authRealm = webResponse.Headers.GetValues(Internal.HttpHeaders.TfsFedAuthRealm).FirstOrDefault();
var authIssuer = webResponse.Headers.GetValues(Internal.HttpHeaders.TfsFedAuthIssuer).FirstOrDefault();
var wwwAuthenticate = webResponse.Headers.GetValues(Internal.HttpHeaders.WwwAuthenticate);
if (!String.IsNullOrEmpty(authIssuer) && !String.IsNullOrEmpty(authRealm))
{
return webResponse.StatusCode != HttpStatusCode.Unauthorized || wwwAuthenticate.Any(x => x.StartsWith("TFS-Federated", StringComparison.OrdinalIgnoreCase));
}
}
return false;
}
internal override string GetAuthenticationChallenge(IHttpResponse webResponse)
{
var authRealm = webResponse.Headers.GetValues(Internal.HttpHeaders.TfsFedAuthRealm).FirstOrDefault();
var authIssuer = webResponse.Headers.GetValues(Internal.HttpHeaders.TfsFedAuthIssuer).FirstOrDefault();
return string.Format(CultureInfo.InvariantCulture, "TFS-Federated realm={0}, issuer={1}", authRealm, authIssuer);
}
/// <summary>
/// Creates a provider for retrieving security tokens for the provided credentials.
/// </summary>
/// <returns>An issued token provider for the current credential</returns>
protected override IssuedTokenProvider OnCreateTokenProvider(
Uri serverUrl,
IHttpResponse response)
{
// The response is only null when attempting to determine the most appropriate token provider to
// use for the connection. The only way we should do anything here is if we have an initial token
// since that means we can present something without making a server call.
if (response == null && base.InitialToken == null)
{
return null;
}
Uri signInUrl = null;
String realm = string.Empty;
if (response != null)
{
realm = response.Headers.GetValues(Internal.HttpHeaders.TfsFedAuthRealm).FirstOrDefault();
signInUrl = new Uri(new Uri(response.Headers.GetValues(Internal.HttpHeaders.TfsFedAuthIssuer).FirstOrDefault()).GetLeftPart(UriPartial.Authority));
}
return new VssServiceIdentityTokenProvider(this, serverUrl, signInUrl, realm, m_innerHandler);
}
private readonly String m_userName;
private readonly String m_password;
[NonSerialized]
private readonly DelegatingHandler m_innerHandler = null;
}
}

View File

@@ -1,114 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using GitHub.Services.Common.Internal;
namespace GitHub.Services.Common
{
/// <summary>
/// Provides simple web token used for OAuth authentication.
/// </summary>
[Serializable]
public sealed class VssServiceIdentityToken : IssuedToken
{
/// <summary>
/// Initializes a new <c>VssServiceIdentityToken</c> instance with the specified token value.
/// </summary>
/// <param name="token">The token value as a string</param>
public VssServiceIdentityToken(string token)
{
ArgumentUtility.CheckStringForNullOrEmpty(token, "token");
m_token = token;
//.ValidFrom = DateTime.UtcNow;
// Read out the expiration time for the ValidTo field if we can find it
Dictionary<string, string> nameValues;
if (TryGetNameValues(token, out nameValues))
{
string expiresOnValue;
if (nameValues.TryGetValue(c_expiresName, out expiresOnValue))
{
// The time is represented as standard epoch
// base.ValidTo = s_epoch.AddSeconds(Convert.ToUInt64(expiresOnValue, CultureInfo.CurrentCulture));
}
}
}
public String Token
{
get
{
return m_token;
}
}
protected internal override VssCredentialsType CredentialType
{
get
{
return VssCredentialsType.ServiceIdentity;
}
}
internal override void ApplyTo(IHttpRequest request)
{
request.Headers.SetValue(Internal.HttpHeaders.Authorization, "WRAP access_token=\"" + m_token + "\"");
}
internal static VssServiceIdentityToken ExtractToken(string responseValue)
{
// Extract the actual token string
string token = UriUtility.UrlDecode(responseValue
.Split('&')
.Single(value => value.StartsWith("wrap_access_token=", StringComparison.OrdinalIgnoreCase))
.Split('=')[1], VssHttpRequestSettings.Encoding);
return new VssServiceIdentityToken(token);
}
internal static bool TryGetNameValues(
string token,
out Dictionary<string, string> tokenValues)
{
tokenValues = null;
if (string.IsNullOrEmpty(token))
{
return false;
}
tokenValues =
token
.Split('&')
.Aggregate(
new Dictionary<string, string>(),
(dict, rawNameValue) =>
{
if (rawNameValue == string.Empty)
{
return dict;
}
string[] nameValue = rawNameValue.Split('=');
if (nameValue.Length != 2)
{
return dict;
}
if (dict.ContainsKey(nameValue[0]) == true)
{
return dict;
}
dict.Add(UriUtility.UrlDecode(nameValue[0]), UriUtility.UrlDecode(nameValue[1]));
return dict;
});
return true;
}
private string m_token;
private const string c_expiresName = "ExpiresOn";
}
}

View File

@@ -1,201 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using GitHub.Services.Common.Diagnostics;
using GitHub.Services.Common.Internal;
namespace GitHub.Services.Common
{
internal sealed class VssServiceIdentityTokenProvider : IssuedTokenProvider
{
public VssServiceIdentityTokenProvider(
VssServiceIdentityCredential credential,
Uri serverUrl,
Uri signInUrl,
string realm,
DelegatingHandler innerHandler)
: this(credential, serverUrl, signInUrl, realm)
{
m_innerHandler = innerHandler;
}
public VssServiceIdentityTokenProvider(
VssServiceIdentityCredential credential,
Uri serverUrl,
Uri signInUrl,
string realm)
: base(credential, serverUrl, signInUrl)
{
Realm = realm;
}
protected override string AuthenticationParameter
{
get
{
if (string.IsNullOrEmpty(this.Realm) && this.SignInUrl == null)
{
return string.Empty;
}
else
{
return string.Format(CultureInfo.InvariantCulture, "issuer=\"{0}\", realm=\"{1}\"", this.SignInUrl, this.Realm);
}
}
}
protected override String AuthenticationScheme
{
get
{
return "TFS-Federated";
}
}
/// <summary>
/// Gets the simple web token credential from which this provider was created.
/// </summary>
public new VssServiceIdentityCredential Credential
{
get
{
return (VssServiceIdentityCredential)base.Credential;
}
}
/// <summary>
/// Gets a value indicating whether or not a call to get token will require interactivity.
/// </summary>
public override Boolean GetTokenIsInteractive
{
get
{
return false;
}
}
/// <summary>
/// Gets the realm for the token provider.
/// </summary>
public String Realm
{
get;
}
protected internal override bool IsAuthenticationChallenge(IHttpResponse webResponse)
{
if (!base.IsAuthenticationChallenge(webResponse))
{
return false;
}
// This means we were proactively constructed without any connection information. In this case
// we return false to ensure that a new provider is reconstructed with all appropriate configuration
// to retrieve a new token.
if (this.SignInUrl == null)
{
return false;
}
string authRealm = webResponse.Headers.GetValues(HttpHeaders.TfsFedAuthRealm).FirstOrDefault();
string authIssuer = webResponse.Headers.GetValues(HttpHeaders.TfsFedAuthIssuer).FirstOrDefault();
Uri signInUrl = new Uri(new Uri(authIssuer).GetLeftPart(UriPartial.Authority), UriKind.Absolute);
// Make sure that the values match our stored values. This way if the values change we will be thrown
// away and a new instance with correct values will be constructed.
return this.Realm.Equals(authRealm, StringComparison.OrdinalIgnoreCase) &&
Uri.Compare(this.SignInUrl, signInUrl, UriComponents.AbsoluteUri, UriFormat.Unescaped, StringComparison.OrdinalIgnoreCase) == 0;
}
/// <summary>
/// Issues a request to synchronously retrieve a token for the associated credential.
/// </summary>
/// <param name="failedToken"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected override async Task<IssuedToken> OnGetTokenAsync(
IssuedToken failedToken,
CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(this.Credential.UserName) ||
string.IsNullOrEmpty(this.Credential.Password))
{
return null;
}
VssTraceActivity traceActivity = VssTraceActivity.Current;
using (HttpClient client = new HttpClient(CreateMessageHandler(), false))
{
client.BaseAddress = this.SignInUrl;
KeyValuePair<string, string>[] values = new KeyValuePair<string, string>[]
{
new KeyValuePair<string, string>("wrap_name", this.Credential.UserName),
new KeyValuePair<string, string>("wrap_password", this.Credential.Password),
new KeyValuePair<string, string>("wrap_scope", this.Realm),
};
Uri url = new Uri("WRAPv0.9/", UriKind.Relative);
FormUrlEncodedContent content = new FormUrlEncodedContent(values);
using (HttpResponseMessage response = await client.PostAsync(url, content, cancellationToken).ConfigureAwait(false))
{
string responseValue = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
return VssServiceIdentityToken.ExtractToken(responseValue);
}
else
{
VssHttpEventSource.Log.AuthenticationError(traceActivity, this, responseValue);
return null;
}
}
}
}
private HttpMessageHandler CreateMessageHandler()
{
var retryOptions = new VssHttpRetryOptions()
{
RetryableStatusCodes =
{
VssNetworkHelper.TooManyRequests,
HttpStatusCode.InternalServerError,
},
};
HttpMessageHandler innerHandler;
if (m_innerHandler != null)
{
if (m_innerHandler.InnerHandler == null)
{
m_innerHandler.InnerHandler = new HttpClientHandler();
}
innerHandler = m_innerHandler;
}
else
{
innerHandler = new HttpClientHandler();
}
// Inherit proxy setting from VssHttpMessageHandler
var httpClientHandler = innerHandler as HttpClientHandler;
if (httpClientHandler != null && VssHttpMessageHandler.DefaultWebProxy != null)
{
httpClientHandler.Proxy = VssHttpMessageHandler.DefaultWebProxy;
httpClientHandler.UseProxy = true;
}
return new VssHttpRetryMessageHandler(retryOptions, innerHandler);
}
private DelegatingHandler m_innerHandler = null;
}
}

View File

@@ -1,137 +0,0 @@
using System;
using System.Linq;
using System.Net;
namespace GitHub.Services.Common
{
/// <summary>
/// Provides a credential for windows authentication against a Visual Studio Service.
/// </summary>
public sealed class WindowsCredential : IssuedTokenCredential
{
/// <summary>
/// Initializes a new <c>WindowsCredential</c> instance using a default user interface provider implementation
/// and the default network credentials.
/// </summary>
public WindowsCredential()
: this(true)
{
}
/// <summary>
/// Initializes a new <c>WindowsCredential</c> instance using a default user interface provider implementation
/// and the default network credentials, if specified.
/// </summary>
/// <param name="useDefaultCredentials">True if the default credentials should be used; otherwise, false</param>
public WindowsCredential(bool useDefaultCredentials)
: this(useDefaultCredentials ? CredentialCache.DefaultCredentials : null)
{
UseDefaultCredentials = useDefaultCredentials;
}
/// <summary>
/// Initializes a new <c>WindowsCredential</c> instance using a default user interface provider implementation
/// and the specified network credentials.
/// </summary>
/// <param name="credentials">The windows credentials which should be used for authentication</param>
public WindowsCredential(ICredentials credentials)
: this(null)
{
m_credentials = credentials;
UseDefaultCredentials = credentials == CredentialCache.DefaultCredentials;
}
/// <summary>
/// Initializes a new <c>WindowsCredential</c> instance using the specified initial token.
/// </summary>
/// <param name="initialToken">An optional token which, if present, should be used before obtaining a new token</param>
public WindowsCredential(WindowsToken initialToken)
: base(initialToken)
{
}
/// <summary>
/// Gets the credentials associated with this windows credential.
/// </summary>
public ICredentials Credentials
{
get
{
return m_credentials;
}
set
{
m_credentials = value;
UseDefaultCredentials = Credentials == CredentialCache.DefaultCredentials;
}
}
public override VssCredentialsType CredentialType
{
get
{
return VssCredentialsType.Windows;
}
}
/// <summary>
/// Gets a value indicating what value was passed to WindowsCredential(bool useDefaultCredentials) constructor
/// </summary>
public Boolean UseDefaultCredentials
{
get;
private set;
}
public override Boolean IsAuthenticationChallenge(IHttpResponse webResponse)
{
if (webResponse == null)
{
return false;
}
if (webResponse.StatusCode == HttpStatusCode.Unauthorized &&
webResponse.Headers.GetValues(Internal.HttpHeaders.WwwAuthenticate).Any(x => AuthenticationSchemeValid(x)))
{
return true;
}
if (webResponse.StatusCode == HttpStatusCode.ProxyAuthenticationRequired &&
webResponse.Headers.GetValues(Internal.HttpHeaders.ProxyAuthenticate).Any(x => AuthenticationSchemeValid(x)))
{
return true;
}
return false;
}
protected override IssuedTokenProvider OnCreateTokenProvider(
Uri serverUrl,
IHttpResponse response)
{
// If we have no idea what kind of credentials we are supposed to be using, don't play a windows token on
// the first request.
if (response == null)
{
return null;
}
if (m_credentials != null)
{
this.InitialToken = new WindowsToken(m_credentials);
}
return new WindowsTokenProvider(this, serverUrl);
}
private static Boolean AuthenticationSchemeValid(String authenticateHeader)
{
return authenticateHeader.StartsWith("Basic", StringComparison.OrdinalIgnoreCase) ||
authenticateHeader.StartsWith("Digest", StringComparison.OrdinalIgnoreCase) ||
authenticateHeader.StartsWith("Negotiate", StringComparison.OrdinalIgnoreCase) ||
authenticateHeader.StartsWith("Ntlm", StringComparison.OrdinalIgnoreCase);
}
private ICredentials m_credentials;
}
}

View File

@@ -1,39 +0,0 @@
using System;
using System.Net;
namespace GitHub.Services.Common
{
public sealed class WindowsToken : IssuedToken, ICredentials
{
internal WindowsToken(ICredentials credentials)
{
this.Credentials = credentials;
}
public ICredentials Credentials
{
get;
}
protected internal override VssCredentialsType CredentialType
{
get
{
return VssCredentialsType.Windows;
}
}
internal override void ApplyTo(IHttpRequest request)
{
// Special-cased by the caller because we implement ICredentials
throw new InvalidOperationException();
}
NetworkCredential ICredentials.GetCredential(
Uri uri,
String authType)
{
return this.Credentials?.GetCredential(uri, authType);
}
}
}

View File

@@ -1,40 +0,0 @@
using System;
using System.Globalization;
using System.Net;
namespace GitHub.Services.Common
{
internal sealed class WindowsTokenProvider : IssuedTokenProvider
{
public WindowsTokenProvider(
WindowsCredential credential,
Uri serverUrl)
: base(credential, serverUrl, serverUrl)
{
}
protected override String AuthenticationScheme
{
get
{
return String.Format(CultureInfo.InvariantCulture, "{0} {1} {2} {3}", AuthenticationSchemes.Negotiate, AuthenticationSchemes.Ntlm, AuthenticationSchemes.Digest, AuthenticationSchemes.Basic);
}
}
public new WindowsCredential Credential
{
get
{
return (WindowsCredential)base.Credential;
}
}
public override Boolean GetTokenIsInteractive
{
get
{
return base.CurrentToken == null;
}
}
}
}

View File

@@ -5,9 +5,6 @@ using System.Globalization;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
#if !NETSTANDARD
using System.Diagnostics.Eventing;
#endif
namespace GitHub.Services.Common.Diagnostics
{
@@ -838,13 +835,6 @@ namespace GitHub.Services.Common.Diagnostics
[NonEvent]
private void SetActivityId(VssTraceActivity activity)
{
#if !NETSTANDARD
if (activity != null)
{
Guid activityId = activity.Id;
EventProvider.SetActivityId(ref activityId);
}
#endif
}
[NonEvent]
@@ -876,15 +866,6 @@ namespace GitHub.Services.Common.Diagnostics
Action<Int32, String> writeEvent)
{
writeEvent(param0, message);
#if !NETSTANDARD
if (EventProvider.GetLastWriteEventError() == EventProvider.WriteEventErrorCode.EventTooBig)
{
foreach (String messagePart in SplitMessage(message))
{
writeEvent(param0, messagePart);
}
}
#endif
}
[NonEvent]
@@ -895,15 +876,6 @@ namespace GitHub.Services.Common.Diagnostics
Action<VssCredentialsType, Int32, String> writeEvent)
{
writeEvent(param0, param1, message);
#if !NETSTANDARD
if (EventProvider.GetLastWriteEventError() == EventProvider.WriteEventErrorCode.EventTooBig)
{
foreach (String messagePart in SplitMessage(message))
{
writeEvent(param0, param1, messagePart);
}
}
#endif
}
[NonEvent]
@@ -914,23 +886,10 @@ namespace GitHub.Services.Common.Diagnostics
Action<VssHttpMethod, String, String> writeEvent)
{
writeEvent(param0, param1, message);
#if !NETSTANDARD
if (EventProvider.GetLastWriteEventError() == EventProvider.WriteEventErrorCode.EventTooBig)
{
foreach (String messagePart in SplitMessage(message))
{
writeEvent(param0, param1, messagePart);
}
}
#endif
}
[NonEvent]
#if !NETSTANDARD
private unsafe void WriteEvent(
#else
private new unsafe void WriteEvent(
#endif
Int32 eventId,
Int32 param0,
String param1)

View File

@@ -1,8 +1,5 @@
using System;
using System.Diagnostics;
#if !NETSTANDARD
using System.Runtime.Remoting.Messaging;
#endif
using System.Runtime.Serialization;
namespace GitHub.Services.Common.Diagnostics
@@ -38,22 +35,11 @@ namespace GitHub.Services.Common.Diagnostics
/// </summary>
public static VssTraceActivity Current
{
#if !NETSTANDARD
get
{
return CallContext.LogicalGetData(VssTraceActivity.PropertyName) as VssTraceActivity;
}
private set
{
CallContext.LogicalSetData(VssTraceActivity.PropertyName, value);
}
#else
get
{
return null;
}
set { }
#endif
}
/// <summary>

View File

@@ -8,84 +8,28 @@ namespace GitHub.Services.Common.Internal
public static class HttpHeaders
{
public const String ActivityId = "ActivityId";
public const String ETag = "ETag";
public const String TfsVersion = "X-TFS-Version";
public const String TfsRedirect = "X-TFS-Redirect";
public const String TfsException = "X-TFS-Exception";
public const String TfsServiceError = "X-TFS-ServiceError";
public const String TfsSessionHeader = "X-TFS-Session";
public const String TfsSoapException = "X-TFS-SoapException";
public const String TfsFedAuthRealm = "X-TFS-FedAuthRealm";
public const String TfsFedAuthIssuer = "X-TFS-FedAuthIssuer";
public const String TfsFedAuthRedirect = "X-TFS-FedAuthRedirect";
public const String VssAuthorizationEndpoint = "X-VSS-AuthorizationEndpoint";
public const String VssPageHandlers = "X-VSS-PageHandlers";
public const String VssE2EID = "X-VSS-E2EID";
public const String VssOrchestrationId = "X-VSS-OrchestrationId";
public const String AuditCorrelationId = "X-VSS-Audit-CorrelationId";
public const String VssOriginUserAgent = "X-VSS-OriginUserAgent";
// Internal Headers that we use in our client.
public const string TfsInstanceHeader = "X-TFS-Instance";
public const string TfsVersionOneHeader = "X-VersionControl-Instance";
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Tfs")]
public const string TfsImpersonate = "X-TFS-Impersonate";
public const string TfsSubjectDescriptorImpersonate = "X-TFS-SubjectDescriptorImpersonate";
public const string MsContinuationToken = "X-MS-ContinuationToken";
public const String VssUserData = "X-VSS-UserData";
public const String VssAgentHeader = "X-VSS-Agent";
public const String VssAuthenticateError = "X-VSS-AuthenticateError";
public const string VssReauthenticationAction = "X-VSS-ReauthenticationAction";
public const string RequestedWith = "X-Requested-With";
public const String VssRateLimitResource = "X-RateLimit-Resource";
public const String VssRateLimitDelay = "X-RateLimit-Delay";
public const String VssRateLimitLimit = "X-RateLimit-Limit";
public const String VssRateLimitRemaining = "X-RateLimit-Remaining";
public const String VssRateLimitReset = "X-RateLimit-Reset";
public const String RetryAfter = "Retry-After";
public const String VssGlobalMessage = "X-VSS-GlobalMessage";
public const String VssRequestRouted = "X-VSS-RequestRouted";
public const String VssUseRequestRouting = "X-VSS-UseRequestRouting";
public const string VssResourceTenant = "X-VSS-ResourceTenant";
public const String VssOverridePrompt = "X-VSS-OverridePrompt";
public const String VssOAuthS2STargetService = "X-VSS-S2STargetService";
public const String VssHostOfflineError = "X-VSS-HostOfflineError";
public const string VssForceMsaPassThrough = "X-VSS-ForceMsaPassThrough";
public const string VssRequestPriority = "X-VSS-RequestPriority";
// This header represents set of ';' delimited mappings (usually one) that are considered by DetermineAccessMapping API
public const string VssClientAccessMapping = "X-VSS-ClientAccessMapping";
// This header is used to download artifacts anonymously.
// N.B. Some resources secured with download tickets (e.g. TFVC files) are still retrieved with the download
// ticket in the query string.
public const string VssDownloadTicket = "X-VSS-DownloadTicket";
public const string IfModifiedSince = "If-Modified-Since";
public const string Authorization = "Authorization";
public const string Location = "Location";
public const string ProxyAuthenticate = "Proxy-Authenticate";
public const string WwwAuthenticate = "WWW-Authenticate";
public const string AfdIncomingRouteKey = "X-FD-RouteKey";
public const string AfdOutgoingRouteKey = "X-AS-RouteKey";
public const string AfdIncomingEndpointList = "X-FD-RouteKeyApplicationEndpointList";
public const string AfdOutgoingEndpointList = "X-AS-RouteKeyApplicationEndpointList";
public const string AfdResponseRef = "X-MSEdge-Ref";
public const string AfdIncomingClientIp = "X-FD-ClientIP";
public const string AfdIncomingSocketIp = "X-FD-SocketIP";
public const string AfdIncomingRef = "X-FD-Ref";
public const string AfdIncomingEventId = "X-FD-EventId";
public const string AfdIncomingEdgeEnvironment = "X-FD-EdgeEnvironment";
public const string AfdOutgoingQualityOfResponse = "X-AS-QualityOfResponse";
public const string AfdOutgoingClientIp = "X-MSEdge-ClientIP";
}
}

View File

@@ -1,553 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace GitHub.Services.Common
{
/// <summary>
/// Provides path normalization/expansion for absolute, relative and UNC-style paths
/// and supports paths that contain more than 248 characters.
/// </summary>
/// <remarks>
/// This utility class can be used in place of the .NET Path and Directory classes
/// that throw System.IO.PathTooLongException when paths are longer than 248 characters
/// </remarks>
public static class LongPathUtility
{
private static Regex AbsolutePathRegEx = new Regex(@"^([a-zA-Z]:\\|\\\\)", RegexOptions.CultureInvariant | RegexOptions.Compiled);
private const int ERROR_FILE_NOT_FOUND = 2;
/// <summary>
/// Returns a list of directory names under the path specified, and optionally all subdirectories
/// </summary>
/// <param name="path">The directory to search</param>
/// <param name="recursiveSearch">Specifies whether the search operation should include only the currect directory or all subdirectories</param>
/// <returns>A list of all subdirectories</returns>
public static IEnumerable<string> EnumerateDirectories(string path, bool recursiveSearch)
{
var directoryPaths = new List<string>();
EnumerateDirectoriesInternal(directoryPaths, path, recursiveSearch);
return directoryPaths;
}
/// <summary>
/// Returns a list of file names under the path specified, and optionally within all subdirectories.
/// </summary>
/// <param name="path">The directory to search</param>
/// <param name="recursiveSearch">Specifies whether the search operation should include only the current directory or all subdirectories</param>
/// <returns>
/// A list of full file names(including path) contained in the directory specified that match the specified search pattern.</returns>
public static IEnumerable<string> EnumerateFiles(string path, bool recursiveSearch)
{
return EnumerateFiles(path, "*", recursiveSearch);
}
/// <summary>
/// Returns an enumerable collection of file names that match a search pattern in a specified path,
/// and optionally searches subdirectories.
/// </summary>
/// <param name="path">The directory to search</param>
/// <param name="matchPattern">The search string to match against the names of the files</param>
/// <param name="recursiveSearch">Specifies whether the search operation should include only the current directory or all subdirectories</param>
/// <returns>
/// A list of full file names(including path) contained in the directory specified (and subdirectories optionally) that match the specified pattern.
/// </returns>
public static IEnumerable<string> EnumerateFiles(string path, string matchPattern, bool recursiveSearch)
{
if (!DirectoryExists(path))
{
throw new DirectoryNotFoundException($"The path '{path}' is not a valid directory.");
}
var filePaths = new List<string>();
EnumerateFilesInternal(filePaths, path, matchPattern, recursiveSearch);
return filePaths;
}
/// <summary>
/// Returns true/false whether the file exists. This method inspects the
/// file system attributes and supports files without extensions (ex: DIRS, Sources). This method
/// supports file paths that are longer than 260 characters.
/// </summary>
/// <param name="filePath">The file path to inspect</param>
/// <returns>
/// True if the file exists or false if not
/// </returns>
public static bool FileExists(string filePath)
{
return FileOrDirectoryExists(filePath, isDirectory: false);
}
/// <summary>
/// Returns true/false whether the directory exists. This method inspects the
/// file system attributes and supports files without extensions (ex: DIRS, Sources). This method
/// supports file paths that are longer than 260 characters.
/// </summary>
/// <param name="directoryPath">The file path to inspect</param>
/// <returns>
/// True if the directory exists or false if not
/// </returns>
public static bool DirectoryExists(string directoryPath)
{
return FileOrDirectoryExists(directoryPath, isDirectory: true);
}
private static bool FileOrDirectoryExists(string filePath, bool isDirectory)
{
if (String.IsNullOrWhiteSpace(filePath))
{
throw new ArgumentException("A path to the file is required and cannot be null, empty or whitespace", "filePath");
}
bool pathExists = false;
// File names may or may not include an extension (ex: DIRS, Sources). We have to look at the attributes
// on the file system object in order to distinguish a directory from a file
var attributes = (FlagsAndAttributes)NativeMethods.GetFileAttributes(filePath);
if (attributes != FlagsAndAttributes.InvalidFileAttributes)
{
bool pathIsDirectory = (attributes & FlagsAndAttributes.Directory) == FlagsAndAttributes.Directory;
if (pathIsDirectory == isDirectory)
{
pathExists = true;
}
}
return pathExists;
}
/// <summary>
/// Returns the fully expanded/normalized path. This method supports paths that are
/// longer than 248 characters.
/// </summary>
/// <param name="path">The file or directory path</param>
/// <returns></returns>
public static string GetFullNormalizedPath(string path)
{
if (String.IsNullOrWhiteSpace(path))
{
throw new ArgumentException("A path is required and cannot be null, empty or whitespace", "path");
}
string outPath = path;
// We need the length of the absolute path in order to prepare a buffer of
// the correct size
uint bufferSize = NativeMethods.GetFullPathName(path, 0, null, null);
int lastWin32Error = Marshal.GetLastWin32Error();
if (bufferSize > 0)
{
var absolutePath = new StringBuilder((int)bufferSize);
uint length = NativeMethods.GetFullPathName(path, bufferSize, absolutePath, null);
lastWin32Error = Marshal.GetLastWin32Error();
if (length > 0)
{
outPath = absolutePath.ToString();
}
else
{
// Path resolution failed
throw new Win32Exception(
lastWin32Error,
String.Format(
CultureInfo.InvariantCulture,
"Path normalization/expansion failed. The path length was not returned by the Kernel32 subsystem for '{0}'.",
path
)
);
}
}
else
{
// Path resolution failed and the path length could not
// be determined
throw new Win32Exception(
lastWin32Error,
String.Format(
CultureInfo.InvariantCulture,
"Path normalization/expansion failed. A full path was not returned by the Kernel32 subsystem for '{0}'.",
path
)
);
}
return outPath != null ? outPath.TrimEnd('\\') : null;
}
/// <summary>
/// Determines whether the specified path is an absolute path or not.
/// </summary>
/// <param name="path">The path to be tested.</param>
/// <returns>
/// <c>true</c> if the path is absolute; otherwise, <c>false</c>.
/// </returns>
public static bool IsAbsolutePath(string path)
{
return LongPathUtility.AbsolutePathRegEx.Match(path).Success;
}
public static string RemoveExtendedLengthPathPrefix(string inPath)
{
string outPath = inPath;
if (!String.IsNullOrWhiteSpace(inPath))
{
if (inPath.StartsWith("\\", StringComparison.OrdinalIgnoreCase))
{
// ex: \\?\UNC\server\share to \\server\share
outPath = inPath.Replace(@"\\?\UNC", @"\");
// ex: \\?\c:\windows to c:\windows
outPath = outPath.Replace(@"\\?\", String.Empty);
}
}
return outPath;
}
private static string CombinePaths(string pathA, string pathB)
{
if (pathA == null)
{
throw new ArgumentNullException("pathA");
}
if (pathB == null)
{
throw new ArgumentNullException("pathB");
}
// The Path class does not suffer from the 248/260 character limitation
// that the File and Directory classes do.
return Path.Combine(
pathA.TrimEnd('\\'),
pathB.TrimStart('\\')
);
}
private static string ConvertToExtendedLengthPath(string path)
{
string extendedLengthPath = GetFullNormalizedPath(path);
if (!String.IsNullOrWhiteSpace(extendedLengthPath))
{
//no need to modify- it's already unicode
if (!extendedLengthPath.StartsWith(@"\\?", StringComparison.OrdinalIgnoreCase))
{
// ex: \\server\share
if (extendedLengthPath.StartsWith(@"\\", StringComparison.OrdinalIgnoreCase))
{
// make it \\?\UNC\server\share
extendedLengthPath = String.Format(
CultureInfo.InvariantCulture,
@"\\?\UNC{0}",
extendedLengthPath.Substring(1)
);
}
else //not unicode already, and not UNC
{
extendedLengthPath = String.Format(
CultureInfo.InvariantCulture,
@"\\?\{0}",
extendedLengthPath
);
}
}
}
return extendedLengthPath;
}
private static IEnumerable<string> EnumerateDirectoriesInPath(string path)
{
SafeFindHandle handle = null;
var findData = new FindData();
var childDirectories = new List<string>();
using (handle = NativeMethods.FindFirstFile(CombinePaths(ConvertToExtendedLengthPath(path), "*"), findData))
{
if (!handle.IsInvalid)
{
bool searchComplete = false;
do
{
// skip the dot directories
if (!findData.fileName.Equals(@".") && !findData.fileName.Equals(@".."))
{
if ((findData.fileAttributes & (int)FileAttributes.Directory) != 0)
{
childDirectories.Add(RemoveExtendedLengthPathPrefix(CombinePaths(path, findData.fileName)));
}
}
if (NativeMethods.FindNextFile(handle, findData))
{
if (handle.IsInvalid)
{
throw new Win32Exception(
Marshal.GetLastWin32Error(),
String.Format(
CultureInfo.InvariantCulture,
"Enumerating subdirectories for path '{0}' failed.",
path
)
);
}
}
else
{
searchComplete = true;
}
} while (!searchComplete);
}
}
return childDirectories;
}
private static IEnumerable<string> EnumerateFilesInPath(string path, string matchPattern)
{
SafeFindHandle handle = null;
var findData = new FindData();
var fullFilePaths = new List<string>();
using (handle = NativeMethods.FindFirstFile(CombinePaths(ConvertToExtendedLengthPath(path), matchPattern), findData))
{
int lastWin32Error = Marshal.GetLastWin32Error();
if (handle.IsInvalid)
{
if (lastWin32Error != ERROR_FILE_NOT_FOUND)
{
throw new Win32Exception(
lastWin32Error,
String.Format(CultureInfo.InvariantCulture, "Enumerating files for path '{0}' failed.", path)
);
}
}
else
{
bool searchComplete = false;
do
{
// skip the dot directories
if (!findData.fileName.Equals(@".") && !findData.fileName.Equals(@".."))
{
if ((findData.fileAttributes & (int)FileAttributes.Directory) == 0)
{
fullFilePaths.Add(RemoveExtendedLengthPathPrefix(CombinePaths(path, findData.fileName)));
}
}
if (NativeMethods.FindNextFile(handle, findData))
{
lastWin32Error = Marshal.GetLastWin32Error();
if (handle.IsInvalid)
{
throw new Win32Exception(
lastWin32Error,
String.Format(
CultureInfo.InvariantCulture,
"Enumerating subdirectories for path '{0}' failed.",
path
)
);
}
}
else
{
searchComplete = true;
}
} while (!searchComplete);
}
}
return fullFilePaths;
}
private static void EnumerateFilesInternal(List<string> filePaths, string path, string matchPattern, bool recursiveSearch)
{
var fullFilePaths = EnumerateFilesInPath(path, matchPattern);
if (fullFilePaths.Any())
{
lock (filePaths)
{
filePaths.AddRange(fullFilePaths);
}
}
if (recursiveSearch)
{
var directorySearchPaths = EnumerateDirectoriesInPath(path);
if (directorySearchPaths.Any())
{
Parallel.ForEach(
directorySearchPaths,
(searchPath) =>
{
EnumerateFilesInternal(filePaths, searchPath, matchPattern, recursiveSearch);
}
);
}
}
}
public static void EnumerateDirectoriesInternal(List<string> directoryPaths, string path, bool recursiveSearch)
{
var directorySearchPaths = EnumerateDirectoriesInPath(path);
if (directorySearchPaths.Any())
{
lock (directoryPaths)
{
directoryPaths.AddRange(directorySearchPaths);
}
if (recursiveSearch)
{
// This will not ensure that the directory paths are added to the list
// in alphabetical order but does provide performance 2 - 4 times better than the
// canonical Directory.GetDirectories() method.
Parallel.ForEach(
directorySearchPaths,
(searchPath) =>
{
EnumerateDirectoriesInternal(directoryPaths, searchPath, recursiveSearch);
}
);
}
}
}
/// <summary>
/// Kernel32.dll native interop methods for use with utility file/path parsing
/// operations
/// </summary>
private static class NativeMethods
{
private const string Kernel32Dll = "kernel32.dll";
[DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FindClose(IntPtr hFindFile);
[SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "FindData.alternateFileName")]
[SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "FindData.fileName")]
[DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
public static extern SafeFindHandle FindFirstFile(
[MarshalAs(UnmanagedType.LPTStr)]
string fileName,
[In, Out] FindData findFileData
);
[SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "FindData.alternateFileName")]
[SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "FindData.fileName")]
[DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FindNextFile(SafeFindHandle hFindFile, [In, Out] FindData lpFindFileData);
[DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
public static extern int GetFileAttributes(string lpFileName);
[DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
public static extern uint GetFullPathName(
[MarshalAs(UnmanagedType.LPTStr)]
string lpFileName,
uint nBufferLength,
[Out]
StringBuilder lpBuffer,
StringBuilder lpFilePart
);
}
//for mapping to the WIN32_FIND_DATA native structure
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed.")]
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed.")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private sealed class FindData
{
// NOTE:
// Although it may seem correct to Marshal the string members of this class as UnmanagedType.LPWStr, they
// must explicitly remain UnmanagedType.ByValTStr with the size constraints noted. Otherwise we end up with
// COM Interop exceptions while trying to marshal the data across the PInvoke boundaries. We thus require the StyleCop
// suppressions on the NativeMethods.FindNextFile() method above.
public int fileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME creationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME lastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME lastWriteTime;
public int nFileSizeHigh;
public int nFileSizeLow;
public int dwReserved0;
public int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string fileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string alternateFileName;
}
//A Win32 safe find handle in which a return value of -1 indicates it's invalid
private sealed class SafeFindHandle : Microsoft.Win32.SafeHandles.SafeHandleMinusOneIsInvalid
{
public SafeFindHandle()
: base(true)
{
return;
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
protected override bool ReleaseHandle()
{
return NativeMethods.FindClose(handle);
}
}
[Flags]
private enum FlagsAndAttributes : uint
{
None = 0x00000000,
Readonly = 0x00000001,
Hidden = 0x00000002,
System = 0x00000004,
Directory = 0x00000010,
Archive = 0x00000020,
Device = 0x00000040,
Normal = 0x00000080,
Temporary = 0x00000100,
SparseFile = 0x00000200,
ReparsePoint = 0x00000400,
Compressed = 0x00000800,
Offline = 0x00001000,
NotContentIndexed = 0x00002000,
Encrypted = 0x00004000,
Write_Through = 0x80000000,
Overlapped = 0x40000000,
NoBuffering = 0x20000000,
RandomAccess = 0x10000000,
SequentialScan = 0x08000000,
DeleteOnClose = 0x04000000,
BackupSemantics = 0x02000000,
PosixSemantics = 0x01000000,
OpenReparsePoint = 0x00200000,
OpenNoRecall = 0x00100000,
FirstPipeInstance = 0x00080000,
InvalidFileAttributes = 0xFFFFFFFF // Returned by GetFileAttributes on Non existant path
}
}
}

View File

@@ -218,7 +218,6 @@ namespace GitHub.Services.Common
}
}
#if NETSTANDARD
/// <summary>
/// Portable compliant way to get a constructor with specified arguments. This will return a constructor that is public or private as long as the arguments match. NULL will be returned if there is no match.
/// Note that it will pick the first one it finds that matches, which is not necesarily the best match.
@@ -263,7 +262,6 @@ namespace GitHub.Services.Common
}
return null;
}
#endif
private static PropertyInfo GetPublicInstancePropertyInfo(Type type, string name)
{

View File

@@ -1,18 +1,4 @@
// ************************************************************************************************
// Microsoft Team Foundation
//
// Microsoft Confidential
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: VssStringComparer.cs
// Area: Team Foundation
// Classes: VssStringComparer
// Contents: The Team Foundation string comparison class provides inner classes
// that are used to provide semantic-specific Equals and Compare methods
// and a semantic-specific StringComparer instance. New semantics should
// be added on an as-needed basis.
// ************************************************************************************************
using System;
using System;
using System.Diagnostics;
namespace GitHub.Services.Common

View File

@@ -13,9 +13,6 @@ namespace GitHub.Services.Common.Internal
{
[EditorBrowsable(EditorBrowsableState.Never)]
#if !NETSTANDARD
[CLSCompliant(false)]
#endif
public static class XmlUtility
{
internal static FileStream OpenFile(String path, FileShare sharing, Boolean saveFile)

View File

@@ -5,16 +5,6 @@ using System.Diagnostics.CodeAnalysis;
namespace GitHub.Services.Common
{
public static class AdminConstants
{
/// <summary>
/// Each incoming web request is assigned a server process id, this constant defines
/// an element within the Context.Items[] to hold that value.
/// </summary>
public const String ServerProcessID = "serverProcessID";
public const String ApplicationName = "ApplicationName";
}
[GenerateSpecificConstants]
public static class IdentityConstants
{
@@ -352,370 +342,6 @@ namespace GitHub.Services.Common
public static readonly ISet<string> WhiteListedProperties = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
}
public static class DirectoryRoleConstants
{
/// Name of the directory role that represents "Company Administrator/Global Admin"
public const string CompanyAdministrator = "Company Administrator";
}
// Used with Registration entries
[GenerateSpecificConstants]
public static class ToolNames
{
public const string Framework = "Framework";
[GenerateConstant]
public const string VersionControl = "VersionControl";
[GenerateConstant]
public const string WorkItemTracking = "WorkItemTracking";
[GenerateConstant]
public const string RemoteWorkItemTracking = "RemoteWorkItemTracking";
public const string CoreServices = "vstfs";
public const string Warehouse = "Reports";
[GenerateConstant]
public const string TeamBuild = "Build";
public const string ProxyServer = "ps";
public const string TeamFoundation = "vstfs";
public const string SharePoint = "Wss";
[GenerateConstant]
public const string TestManagement = "TestManagement";
public const string LabManagement = "LabManagement";
public const string ReleaseManagement = "ReleaseManagement";
public const string SyncService = "SyncService";
public const string TestRig = "TestRig";
public const string TSWebAccess = "TSWebAccess";
public const string ProjectServer = "ProjectServer";
public const string DeploymentRig = "DeploymentRig";
public const string TeamProjects = "TeamProjects"; // contains specific project registration entries (project portal, process guidance and doc url)
public const string Discussion = "Discussion";
[GenerateConstant]
public const string Requirements = "Requirements";
[GenerateConstant]
public const string Hyperlink = "Hyperlink";
public const string Classification = "Classification";
[GenerateConstant]
public const string Legacy = "Legacy";
[GenerateConstant]
public const string CodeSense = "CodeSense";
[GenerateConstant]
public const string Git = "Git";
[GenerateConstant]
public const string CodeReview = "CodeReview";
[GenerateConstant]
public const string ProjectDownload = "ProjectDownload";
public const string DistributedTask = "DistributedTask";
[GenerateConstant]
public const string Wiki = "Wiki";
public const string Search = "Search";
[GenerateConstant]
public const string GitHub = "GitHub";
}
// Artifact types
[GenerateSpecificConstants]
public static class ArtifactTypeNames
{
public const string Project = "TeamProject";
public const string Node = "Node";
public const string Collector = "Collector";
public const string TestResult = "TestResult";
[GenerateConstant]
public const string TcmResult = "TcmResult";
[GenerateConstant]
public const string TcmResultAttachment = "TcmResultAttachment";
[GenerateConstant]
public const string TcmTest = "TcmTest";
[GenerateConstant]
public const string Build = "Build";
public const string BuildAgent = "Agent";
public const string BuildDefinition = "Definition";
public const string BuildController = "Controller";
public const string BuildGroup = "Group";
public const string BuildRequest = "Request";
public const string BuildServiceHost = "ServiceHost";
[GenerateConstant]
public const string VersionedItem = "VersionedItem";
[GenerateConstant]
public const string LatestItemVersion = "LatestItemVersion";
[GenerateConstant]
public const string Changeset = "Changeset";
public const string Label = "Label";
[GenerateConstant]
public const string Shelveset = "Shelveset";
public const string ShelvedItem = "ShelvedItem";
[GenerateConstant]
public const string WorkItem = "WorkItem";
public const string Query = "Query";
public const string Results = "Results";
public const string LabEnvironment = "LabEnvironment";
public const string LabTemplate = "LabTemplate";
public const string LabSystem = "LabSystem";
public const string TeamProjectHostGroup = "TeamProjectHostGroup";
public const string TeamProjectLibraryShare = "TeamProjectLibraryShare";
public const string TeamProjectCollectionLibraryShare = "TeamProjectCollectionLibraryShare";
public const string TeamProjectCollectionHostGroup = "TeamProjectCollectionHostGroup";
public const string TestMachine = "TestMachine";
[GenerateConstant]
public const string Storyboard = "Storyboard";
[GenerateConstant]
public const string Commit = "Commit";
public const string LaunchLatestVersionedItem = "LaunchLatestVersionedItem";
[GenerateConstant]
public const string CodeReviewId = "CodeReviewId";
[GenerateConstant]
public const string CodeReviewSdkId = "ReviewId";
[GenerateConstant]
public const string PullRequestId = "PullRequestId";
[GenerateConstant]
public const string ProjectDownloadProject = "Project";
/// <summary>
/// A Git Ref
/// </summary>
[GenerateConstant]
public const string Ref = "Ref";
public const string TaskAgentPoolMaintenance = "PoolMaintenance";
[GenerateConstant]
public const string WikiPage = "WikiPage";
// GitHub
[GenerateConstant]
public const string PullRequest = "PullRequest";
[GenerateConstant]
public const string Issue = "Issue";
}
/// <summary>
/// Constant strings used in Notifications
/// </summary>
public static class NotificationConstants
{
/// <summary>
/// Macro used in subscriptions which will be replaced by the project name when evaluated
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.MyProjectNameMacro in assembly MS.VS.Services.Notifications.WebApi")]
public const String MyProjectNameMacro = "@@MyProjectName@@";
/// <summary>
/// Macro used in subscriptions which will be replaced by the subscriber's Display Name when evaluated
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.MyDisplayNameMacro in assembly MS.VS.Services.Notifications.WebApi")]
public const String MyDisplayNameMacro = "@@MyDisplayName@@";
/// <summary>
/// Macro used in subscriptions which will be replaced by the subscriber's Unique User Name when evaluated
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.MyUniqueNameMacro in assembly MS.VS.Services.Notifications.WebApi")]
public const String MyUniqueNameMacro = "@@MyUniqueName@@";
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.SingleQuoteNameMacro in assembly MS.VS.Services.Notifications.WebApi")]
public const String SingleQuoteNameMacro = "@@SQBDQ@@"; //SingleQuoteBetweenDoubleQuotes
[Obsolete]
public const String SingleQuoteValue = "\"'\""; //"'"
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.DoubleQuoteNameMacro in assembly MS.VS.Services.Notifications.WebApi")]
public const String DoubleQuoteNameMacro = "@@DQBSQ@@"; //DoubleQuoteBetweenSingleQuotes
[Obsolete]
public const String DoubleQuoteValue = "'\"'"; //'"'
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.SingleQuoteCharMacro in assembly MS.VS.Services.Notifications.WebApi")]
public const String SingleQuoteCharMacro = "@@SingleQuote@@";
[Obsolete]
public const String SingleQuoteCharValue = "'";
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.DoubleQuoteCharMacro in assembly MS.VS.Services.Notifications.WebApi")]
public const String DoubleQuoteCharMacro = "@@DoubleQuote@@";
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.DoubleQuoteCharValue in assembly MS.VS.Services.Notifications.WebApi")]
public const String DoubleQuoteCharValue = "\"";
/// <summary>
/// Token used in subscription addresses to identify dynamic delivery targets computed from the source event
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.DynamicTargetsToken in assembly MS.VS.Services.Notifications.WebApi")]
public const String DynamicTargetsToken = "@@";
/// <summary>
/// TeamFoundationIdentity property name for a user's custom list of Email addresses to receive notifications at
/// </summary>
public const String CustomNotificationAddressesIdentityProperty = "CustomNotificationAddresses";
/// <summary>
/// TeamFoundationIdentity propery name for a user's confirmed Email address to receive notifications. This is used in Hosted environments only.
/// </summary>
public const string ConfirmedNotificationAddressIdentityProperty = "ConfirmedNotificationAddress";
/// <summary>
/// The name of the WorkItemChangedEvent
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.LegacyNames.WorkItemChangedEvent in assembly MS.VS.Services.Notifications.WebApi")]
public const string WorkItemChangedEventTypeName = "WorkItemChangedEvent";
/// <summary>
/// The name of the BuildStatusChangedEvent type
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.LegacyNames.BuildStatusChangeEvent in assembly MS.VS.Services.Notifications.WebApi")]
public const String BuildStatusChangeEventName = "BuildStatusChangeEvent";
/// <summary>
/// The name of the BuildCompletedEvent type
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.LegacyNames.BuildCompletedEvent in assembly MS.VS.Services.Notifications.WebApi")]
public const String BuildCompletedEventName = "BuildCompletedEvent";
/// <summary>
/// The name of the CheckinEvent type
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.LegacyNames.CheckinEvent in assembly MS.VS.Services.Notifications.WebApi")]
public const String CheckinEventName = "CheckinEvent";
/// <summary>
/// The name of the CodeReviewChangedEvent type
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.LegacyNames.CodeReviewChangedEvent in assembly MS.VS.Services.Notifications.WebApi")]
public const String CodeReviewChangedEventName = "CodeReviewChangedEvent";
/// <summary>
/// The name of the GitPushEvent type
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.LegacyNames.GitPushEvent in assembly MS.VS.Services.Notifications.WebApi")]
public const String GitPushEventName = "GitPushEvent";
/// <summary>
/// The name of the GitPullRequestEvent type
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.LegacyNames.GitPullRequestEvent in assembly MS.VS.Services.Notifications.WebApi")]
public const String GitPullRequestEventName = "GitPullRequestEvent";
/// <summary>
/// The relative path to the alerts admin web page
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationUrlConstants.AlertsPageRelativePath in assembly MS.VS.Services.Notifications.WebApi")]
public const String AlertsPageRelativePath = "{0}#id={1}&showteams={2}";
/// <summary>
/// The alerts page name
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationUrlConstants.AlertsPage in assembly MS.VS.Services.Notifications.WebApi")]
public const String AlertsPage = "_Alerts";
/// <summary>
/// The admin alerts page
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationUrlConstants.AlertsAdminPage in assembly MS.VS.Services.Notifications.WebApi")]
public const String AlertsAdminPage = "_admin/_Alerts";
/// <summary>
/// Property used to keep track of how many confirmations were sent for this user. Used to limit the number
/// of confirmations a single user is allowed to send out for their account.
/// The value is updated and monitored by the SendEmailConfirmationJob.
/// </summary>
public const string EmailConfirmationSendDates = "EmailConfirmationSendDates";
/// <summary>
/// Prefix to denote that identity field value have been processed
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.ProcessedFlagCharacter in assembly MS.VS.Services.Notifications.WebApi")]
public const Char ProcessedFlagCharacter = (Char)7;
/// <summary>
/// Prefix to denote that identity field value have been processed and converted to TFID
/// </summary>
/// [Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.ProcessedTfIdFlagCharacter in assembly MS.VS.Services.Notifications.WebApi")]
public const Char ProcessedTfIdFlagCharacter = (Char)11;
/// <summary>
/// Prefix to denote that this is the start of displayname value for this identity field
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.DisplayNameFlagCharacter in assembly MS.VS.Services.Notifications.WebApi")]
public const Char DisplayNameFlagCharacter = '|';
/// <summary>
/// Prefix to denote that this is the start of TFID value for this identity field
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.TfIdFlagCharacter in assembly MS.VS.Services.Notifications.WebApi")]
public const Char TfIdFlagCharacter = '%';
/// <summary>
/// Optional Feature flag to enable escaping Regex expressions when creating Notification subscriptions.
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.FeatureFlags.AllowUserRegexInMatchConditionFeatureFlag in assembly MS.VS.Services.Notifications.WebApi")]
public const string AllowUserRegexInMatchConditionFeatureFlag = "VisualStudio.Services.Notifications.AllowUserRegexInMatchCondition";
/// <summary>
/// The MDM scope name for the notification job
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.MDMConstants.MDMNotificationJobScope in assembly MS.VS.Services.Notifications.WebApi")]
public const string MDMNotificationJobScope = "NotificationJob";
/// <summary>
/// Event processing delay KPI name
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.MDMConstants.EventProcessingDelayKPI in assembly MS.VS.Services.Notifications.WebApi")]
public const string EventProcessingDelayKPI = "EventProcessingDelayInMs";
/// <summary>
/// Event processing delay KPI description
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.MDMConstants.EventProcessingDelayKPIDesc in assembly MS.VS.Services.Notifications.WebApi")]
public const string EventProcessingDelayKPIDesc = "Time taken to start processing an event";
/// <summary>
/// The MDM scope name for the delivery job
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.MDMConstants.MDMDeliveryJobscope in assembly MS.VS.Services.Notifications.WebApi")]
public const string MDMDeliveryJobscope = "NotificationDeliveryJob";
/// <summary>
/// Notification delivery delay KPI name
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.MDMConstants.DeliveryDelayKPI in assembly MS.VS.Services.Notifications.WebApi")]
public const string DeliveryDelayKPI = "NotificationDeliveryDelayInMs";
/// <summary>
/// Notification delivery delay with retries KPI name
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.MDMConstants.DeliveryDelayWithRetriesKPI in assembly MS.VS.Services.Notifications.WebApi")]
public const string DeliveryDelayWithRetriesKPI = "NotificationDeliveryDelayWithRetriesInMs";
/// <summary>
/// Total time taken between the event creation till the notification delivery
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.MDMConstants.TotalProcessingTimeKPI in assembly MS.VS.Services.Notifications.WebApi")]
public const string TotalProcessingTimeKPI = "EventProcessingTimeInMs";
/// <summary>
/// Total time taken between the event creation till the notification delivery
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.MDMConstants.TotalProcessingTimeWithRetriesKPI in assembly MS.VS.Services.Notifications.WebApi")]
public const string TotalProcessingTimeWithRetriesKPI = "EventProcessingTimeWithRetriesInMs";
/// <summary>
/// Notification delivery delay KPI description
/// </summary>
[Obsolete("Moved to GitHub.Services.Notifications.Common.MDMConstants.DeliveryDelayKPIDesc in assembly MS.VS.Services.Notifications.WebApi")]
public const string DeliveryDelayKPIDesc = "Time taken to start deliverying a notification";
// caching key for our notification bridge interface
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.BridgeKey in assembly MS.VS.Services.Notifications.WebApi")]
public const String BridgeKey = "@NotifBridge";
// delivery retry count registryKey
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.RetryCountRegistryKey in assembly MS.VS.Services.Notifications.WebApi")]
public const string RetryCountRegistryKey = "NotificationRetryCount";
// delivery retry count default value
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.RetryCountDefaultValue in assembly MS.VS.Services.Notifications.WebApi")]
public const Int32 RetryCountDefaultValue = 5;
// the collection scope Guid
[Obsolete("Moved to GitHub.Services.Notifications.Common.NotificationFrameworkConstants.CollectionScope in assembly MS.VS.Services.Notifications.WebApi")]
public static Guid CollectionScope = new Guid("00000000-0000-636f-6c6c-656374696f6e");
}
[EditorBrowsable(EditorBrowsableState.Never)]
public class LocationSecurityConstants
{
@@ -732,16 +358,6 @@ namespace GitHub.Services.Common
public const Int32 AllPermissions = Read | Write;
}
[EditorBrowsable(EditorBrowsableState.Never)]
public class SecuritySecurityConstants
{
public static readonly Guid NamespaceId = new Guid("9A82C708-BFBE-4F31-984C-E860C2196781");
public const char Separator = '/';
public const String RootToken = "";
public const int Read = 1;
}
[EditorBrowsable(EditorBrowsableState.Never)]
public class GraphSecurityConstants
{
@@ -753,158 +369,6 @@ namespace GitHub.Services.Common
public const int ReadByPersonalIdentifier = 2;
}
[EditorBrowsable(EditorBrowsableState.Never)]
public static class TeamProjectSecurityConstants
{
public static readonly Guid NamespaceId = new Guid("52D39943-CB85-4d7f-8FA8-C6BAAC873819");
// Existed in Orcas
public static readonly Int32 GenericRead = 1;
public static readonly Int32 GenericWrite = 2;
public static readonly Int32 Delete = 4;
public static readonly Int32 PublishTestResults = 8;
public static readonly Int32 AdministerBuild = 16;
public static readonly Int32 StartBuild = 32;
public static readonly Int32 EditBuildStatus = 64;
public static readonly Int32 UpdateBuild = 128;
public static readonly Int32 DeleteTestResults = 256;
public static readonly Int32 ViewTestResults = 512;
// Dev10 Beta1
public static readonly Int32 ManageTestEnvironments = 2048;
// Dev10 Beta2
public static readonly Int32 ManageTestConfigurations = 4096;
// Dev14 Update 2 / VSO (M91)
public static readonly Int32 WorkItemDelete = 8192;
// Dev14 Update 2 / VSO (M92)
public static readonly Int32 WorkItemMove = 16384;
// Dev14 Update 2 / VSO (M94)
public static readonly Int32 WorkItemPermanentlyDelete = 32768;
// Dev15 / VSO (M99)
public static readonly Int32 Rename = 65536;
/// <summary>
/// The permission required for setting project properties.
/// Introduced in Dev15 Update 2 / VSO (M116).
/// </summary>
public static readonly Int32 ManageProperties = 131072;
/// <summary>
/// The permission required for setting system project properties.
/// Introduced in Dev15 Update 2 / VSO (M116).
/// </summary>
/// <remarks>
/// This permission was excluded from AllPermissions to avoid being unintentionally granted.
/// </remarks>
public static readonly Int32 ManageSystemProperties = 262144;
/// <summary>
/// The permission required for bypassing the project property cache.
/// Introduced in Dev16 / VSO (M118).
/// </summary>
/// <remarks>
/// This permission was excluded from AllPermissions to avoid being unintentionally granted.
/// </remarks>
public static readonly Int32 BypassPropertyCache = 524288;
/// <summary>
/// The permission required for bypassing the rules while updating work items.
/// Introduced in Dev16 / VSO (M126).
/// </summary>
public static readonly Int32 BypassRules= 1048576;
/// <summary>
/// The permission required for suppressing notifications for work item updates.
/// Introduced in Dev16 / VSO (M126).
/// </summary>
public static readonly Int32 SuppressNotifications= 2097152;
/// <summary>
/// The permission required for updating project visibility.
/// Introduced in Dev16 / VSO (M131).
/// </summary>
public static readonly Int32 UpdateVisibility = 4194304;
/// <summary>
/// The permission required for changing the process of the team project
/// Introduced in Dev17 / VSO (M136).
/// </summary>
public static readonly Int32 ChangeProjectsProcess = 8388608;
/// <summary>
/// The permission required for granting access to backlog management. For stakeholder, this would disabled for private project and enabled for public project.
/// Introduced in Dev17 / VSO (M137).
/// </summary>
/// <remarks>
/// This permission was excluded from AllPermissions to avoid being unintentionally granted.
/// </remarks>
public static readonly Int32 AgileToolsBacklogManagement = 16777216;
/// <summary>
/// The permission required for granting access to backlog management. For stakeholder, this is always disabled.
/// Introduced in Dev17 / VSO (M150).
/// </summary>
/// <remarks>
/// This permission was excluded from AllPermissions to avoid being unintentionally granted.
/// </remarks>
public static readonly Int32 AgileToolsPlans = 33554432;
public static readonly Int32 AllPermissions =
GenericRead |
GenericWrite |
Delete |
PublishTestResults |
AdministerBuild |
StartBuild |
EditBuildStatus |
UpdateBuild |
DeleteTestResults |
ViewTestResults |
ManageTestEnvironments |
ManageTestConfigurations |
WorkItemDelete |
WorkItemMove |
WorkItemPermanentlyDelete |
Rename |
ManageProperties |
BypassRules |
SuppressNotifications |
UpdateVisibility |
ChangeProjectsProcess;
public const String ProjectTokenPrefix = "$PROJECT:";
public static String GetToken(String projectUri)
{
if (String.IsNullOrEmpty(projectUri) || !projectUri.StartsWith(ProjectTokenPrefix, StringComparison.OrdinalIgnoreCase))
{
if (projectUri == null)
{
projectUri = String.Empty;
}
return ProjectTokenPrefix + projectUri + ":";
}
return projectUri + ":";
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
public static class ContentValidationSecurityConstants
{
public static readonly Guid NamespaceId = new Guid("B1982126-CB90-4479-BDFD-CBF193241CB8");
public static readonly string ViolationsToken = "Violations";
public const int Read = 1;
public const int Write = 2;
}
public enum WinHttpErrorCode
{
WINHTTP_ERROR_BASE = 12000,

View File

@@ -124,9 +124,6 @@ namespace GitHub.Services.Common
LogException = (bool)info.GetValue("m_logException", typeof(bool));
ReportException = (bool)info.GetValue("m_reportException", typeof(bool));
ErrorCode = (int)info.GetValue("m_errorCode", typeof(int));
#if !NETSTANDARD
LogLevel = (EventLogEntryType)info.GetValue("m_logLevel", typeof(EventLogEntryType));
#endif
EventId = (int)info.GetValue("m_eventId", typeof(int));
}
@@ -137,9 +134,6 @@ namespace GitHub.Services.Common
info.AddValue("m_logException", LogException);
info.AddValue("m_reportException", ReportException);
info.AddValue("m_errorCode", ErrorCode);
#if !NETSTANDARD
info.AddValue("m_logLevel", LogLevel);
#endif
info.AddValue("m_eventId", EventId);
}
@@ -157,22 +151,6 @@ namespace GitHub.Services.Common
}
}
#if !NETSTANDARD
/// <summary>The event log entry type to use when logging the exception</summary>
/// <value>One of the event log entry types: </value>
public EventLogEntryType LogLevel
{
get
{
return m_logLevel;
}
set
{
m_logLevel = value;
}
}
#endif
/// <summary>A user-defined error code.</summary>
public int ErrorCode
{
@@ -279,10 +257,6 @@ namespace GitHub.Services.Common
private bool m_reportException;
private int m_errorCode;
#if !NETSTANDARD
private EventLogEntryType m_logLevel = EventLogEntryType.Warning;
#endif
private int m_eventId = DefaultExceptionEventId;
//From EventLog.cs in Framework.

View File

@@ -33,13 +33,7 @@ namespace GitHub.Services.Common
public VssHttpMessageHandler(
VssCredentials credentials,
VssHttpRequestSettings settings)
: this(credentials, settings,
#if !NETSTANDARD
new WebRequestHandler()
#else
new HttpClientHandler()
#endif
)
: this(credentials, settings, new HttpClientHandler())
{
}
@@ -76,13 +70,7 @@ namespace GitHub.Services.Common
m_transportHandler = transportHandler;
}
#if NETSTANDARD
//.Net Core does not recognize CredentialCache.DefaultCredentials if we wrap them with CredentialWrapper
bool isDefaultCredentials = credentials != null && credentials.Windows != null && credentials.Windows.UseDefaultCredentials;
ApplySettings(m_transportHandler, isDefaultCredentials ? CredentialCache.DefaultCredentials : m_credentialWrapper, this.Settings);
#else
ApplySettings(m_transportHandler, m_credentialWrapper, this.Settings);
#endif
}
/// <summary>
@@ -139,35 +127,6 @@ namespace GitHub.Services.Common
var traceInfo = VssHttpMessageHandlerTraceInfo.GetTraceInfo(request);
traceInfo?.TraceHandlerStartTime();
#if !NETSTANDARD
// This action is deferred from ApplySettings because we want don't want to do it if we aren't
// talking to an HTTPS endpoint.
if (!m_appliedClientCertificatesToTransportHandler &&
request.RequestUri.Scheme == "https")
{
WebRequestHandler webRequestHandler = m_transportHandler as WebRequestHandler;
if (webRequestHandler != null &&
this.Settings.ClientCertificateManager != null &&
this.Settings.ClientCertificateManager.ClientCertificates != null &&
this.Settings.ClientCertificateManager.ClientCertificates.Count > 0)
{
webRequestHandler.ClientCertificates.AddRange(this.Settings.ClientCertificateManager.ClientCertificates);
}
m_appliedClientCertificatesToTransportHandler = true;
}
if (!m_appliedServerCertificateValidationCallbackToTransportHandler &&
request.RequestUri.Scheme == "https")
{
WebRequestHandler webRequestHandler = m_transportHandler as WebRequestHandler;
if (webRequestHandler != null &&
this.Settings.ServerCertificateValidationCallback != null)
{
webRequestHandler.ServerCertificateValidationCallback = this.Settings.ServerCertificateValidationCallback;
}
m_appliedServerCertificateValidationCallbackToTransportHandler = true;
}
#else
if (!m_appliedClientCertificatesToTransportHandler &&
request.RequestUri.Scheme == "https")
{
@@ -201,7 +160,6 @@ namespace GitHub.Services.Common
{
request.Version = HttpVersion.Version11;
}
#endif
IssuedToken token = null;
IssuedTokenProvider provider;
@@ -540,16 +498,11 @@ namespace GitHub.Services.Common
}
}
private static IWebProxy s_defaultWebProxy =
#if !NETSTANDARD
WebRequest.DefaultWebProxy;
#else
// setting this to WebRequest.DefaultWebProxy in NETSTANDARD is causing a System.PlatformNotSupportedException
//.in System.Net.SystemWebProxy.IsBypassed. Comment in IsBypassed method indicates ".NET Core and .NET Native
// code will handle this exception and call into WinInet/WinHttp as appropriate to use the system proxy."
// This needs to be investigated further.
null;
#endif
// setting this to WebRequest.DefaultWebProxy in NETSTANDARD is causing a System.PlatformNotSupportedException
//.in System.Net.SystemWebProxy.IsBypassed. Comment in IsBypassed method indicates ".NET Core and .NET Native
// code will handle this exception and call into WinInet/WinHttp as appropriate to use the system proxy."
// This needs to be investigated further.
private static IWebProxy s_defaultWebProxy = null;
/// <summary>
/// Allows you to set a proxy to be used by all VssHttpMessageHandler requests without affecting the global WebRequest.DefaultWebProxy. If not set it returns the WebRequest.DefaultWebProxy.
@@ -585,13 +538,9 @@ namespace GitHub.Services.Common
private bool m_appliedServerCertificateValidationCallbackToTransportHandler;
private readonly HttpMessageHandler m_transportHandler;
#if NETSTANDARD
//.Net Core does not attempt NTLM schema on Linux, unless ICredentials is a CredentialCache instance
//This workaround may not be needed after this corefx fix is consumed: https://github.com/dotnet/corefx/pull/7923
private sealed class CredentialWrapper : CredentialCache, ICredentials
#else
private sealed class CredentialWrapper : ICredentials
#endif
{
public ICredentials InnerCredentials
{

View File

@@ -44,9 +44,7 @@ namespace GitHub.Services.Common
this.SuppressFedAuthRedirects = true;
this.ClientCertificateManager = null;
this.ServerCertificateValidationCallback = null;
#if NETSTANDARD
this.UseHttp11 = false;
#endif
// If different, we'll also add CurrentCulture to the request headers,
// but UICulture was added first, so it gets first preference
@@ -99,9 +97,7 @@ namespace GitHub.Services.Common
this.ClientCertificateManager = copy.ClientCertificateManager;
this.ServerCertificateValidationCallback = copy.ServerCertificateValidationCallback;
this.MaxRetryRequest = copy.MaxRetryRequest;
#if NETSTANDARD
this.UseHttp11 = copy.UseHttp11;
#endif
}
/// <summary>
@@ -144,7 +140,6 @@ namespace GitHub.Services.Common
set;
}
#if NETSTANDARD
/// <summary>
/// The .NET Core 2.1 runtime switched its HTTP default from HTTP 1.1 to HTTP 2.
/// This causes problems with some versions of the Curl handler on Linux.
@@ -156,7 +151,6 @@ namespace GitHub.Services.Common
get;
set;
}
#endif
/// <summary>
/// Gets or sets the maximum size allowed for response content buffering.
@@ -266,15 +260,6 @@ namespace GitHub.Services.Common
set;
}
#if !NETSTANDARD
/// <summary>
/// Optional implementation used to validate server certificate validation
/// </summary>
public RemoteCertificateValidationCallback ServerCertificateValidationCallback
{
get; set;
}
#else
/// <summary>
/// Optional implementation used to validate server certificate validation
/// </summary>
@@ -283,7 +268,6 @@ namespace GitHub.Services.Common
get;
set;
}
#endif
/// <summary>
/// Number of times to retry a request that has an ambient failure
@@ -359,13 +343,11 @@ namespace GitHub.Services.Common
request.Headers.Add(Internal.HttpHeaders.VssAgentHeader, this.AgentId);
}
#if NETSTANDARD
// Content is being sent as chunked by default in dotnet5.4, which differs than the .net 4.5 behaviour.
if (request.Content != null && !request.Content.Headers.ContentLength.HasValue && !request.Headers.TransferEncodingChunked.HasValue)
{
request.Content.Headers.ContentLength = request.Content.ReadAsByteArrayAsync().Result.Length;
}
#endif
return true;
}

View File

@@ -216,21 +216,13 @@ namespace GitHub.Services.Common
}
}
}
#if !NETSTANDARD
else if (ex is System.Data.Services.Client.DataServiceRequestException ||
ex is System.Data.Services.Client.DataServiceClientException)
{
// WCF exceptions
return true;
}
#endif
return false;
}
/// <summary>
/// Gets the HttpStatusCode which represents a throttling error.
/// </summary>
/// <summary>
/// Gets the HttpStatusCode which represents a throttling error.
/// </summary>
public const HttpStatusCode TooManyRequests = (HttpStatusCode)429;
}
}

View File

@@ -10,30 +10,14 @@ namespace GitHub.Services.Common
// See Toolsets\Version\Version.props for more details.
public const String MajorVersion = "16";
public const String MinorVersion = "0";
public const String BuildVersion = "65000";
public const String PatchVersion = "0";
public const String ProductVersion = MajorVersion + "." + MinorVersion;
// Assembly version (i.e. strong name)
public const String AssemblyMajorVersion = "16";
public const String AssemblyMinorVersion = "0";
public const String AssemblyBuildVersion = "0";
public const String AssemblyPatchVersion = "0";
public const String AssemblyVersion = AssemblyMajorVersion + "." + AssemblyMinorVersion + "." + AssemblyBuildVersion + "." + AssemblyPatchVersion;
// File version
public const String FileMajorVersion = "16";
public const String FileMinorVersion = "255";
public const String FileBuildVersion = "65000";
public const String FilePatchVersion = "0";
public const String FileVersion = FileMajorVersion + "." + FileMinorVersion + "." + FileBuildVersion + "." + FilePatchVersion;
// Derived versions
public const String TfsMajorVersion = "8";
public const String TfsMinorVersion = "0";
public const String TfsProductVersion = TfsMajorVersion + "." + TfsMinorVersion;
// On-premises TFS install folder
public const String TfsInstallDirectory = "Azure DevOps Server 2019";
}
}